├── .gitignore
├── .rvmrc
├── Gemfile
├── Gemfile.lock
├── README.md
├── config.ru
├── intro
├── 01_intro.md
├── book_cover.jpg
├── challenge.png
├── comic.png
├── ok.png
├── rage1.jpg
├── rage2.jpg
└── rage3.jpg
├── make_awesome
├── 01_making_awesome.md
├── 03_bad_ui.md
├── 04_option_parser.md
├── 05_gli.md
├── 06_summary.md
├── 07_other.md
└── zz_bad_system.md
├── opower.png
├── showoff.json
├── styles.css
└── what_is_awesome
├── 01_awesome_defined.md
├── 02_first_class.md
├── 03_play_well.md
├── 04_be_helpful.md
├── cuke_fail.png
└── cuke_pass.png
/.gitignore:
--------------------------------------------------------------------------------
1 | .DS_Store
2 |
--------------------------------------------------------------------------------
/.rvmrc:
--------------------------------------------------------------------------------
1 | rvm use 1.9.2@showoff --create
2 |
--------------------------------------------------------------------------------
/Gemfile:
--------------------------------------------------------------------------------
1 | source :rubygems
2 |
3 | gem "gli", ">= 1.3.2"
4 | gem "showoff"
5 | gem "heroku"
6 | gem "pdfkit"
7 |
--------------------------------------------------------------------------------
/Gemfile.lock:
--------------------------------------------------------------------------------
1 | GEM
2 | remote: http://rubygems.org/
3 | specs:
4 | bluecloth (2.1.0)
5 | gli (1.3.2)
6 | heroku (2.3.6)
7 | launchy (>= 0.3.2)
8 | rest-client (~> 1.6.1)
9 | term-ansicolor (~> 1.0.5)
10 | json (1.5.3)
11 | launchy (2.0.3)
12 | mime-types (1.16)
13 | nokogiri (1.5.0)
14 | pdfkit (0.5.2)
15 | rack (1.3.1)
16 | rest-client (1.6.3)
17 | mime-types (>= 1.16)
18 | showoff (0.4.2)
19 | bluecloth
20 | gli (>= 1.2.5)
21 | json
22 | nokogiri
23 | sinatra
24 | sinatra (1.2.6)
25 | rack (~> 1.1)
26 | tilt (>= 1.2.2, < 2.0)
27 | term-ansicolor (1.0.6)
28 | tilt (1.3.2)
29 |
30 | PLATFORMS
31 | ruby
32 |
33 | DEPENDENCIES
34 | gli (>= 1.3.2)
35 | heroku
36 | pdfkit
37 | showoff
38 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Awesome Command Line Applications in Ruby
2 |
3 | Slides for my talk at OSCON, July, 2011
4 |
5 | # View
6 |
7 | * [View slides online](https://speakerdeck.com/davetron5000/build-awesome-command-line-applications-with-ruby)
8 |
9 | # Building
10 |
11 | git clone http://github.com/davetron5000/awesome-cli-ruby.git
12 | cd awesome-cli-ruby
13 | gem install bundler # use sudo if not using rvm
14 | bundle install # again, use sudo if not using rvm
15 | showoff serve # browse to http://localhost:9090
16 |
17 | # License
18 |
19 | 
Awesome Command Line Applications in Ruby by David Copeland is licensed under a Creative Commons Attribution-Noncommercial-Share Alike 3.0 United States License.
Based on a work at www.github.com.
20 |
--------------------------------------------------------------------------------
/config.ru:
--------------------------------------------------------------------------------
1 | # encoding: UTF-8
2 | require "showoff"
3 | run ShowOff.new
4 |
--------------------------------------------------------------------------------
/intro/01_intro.md:
--------------------------------------------------------------------------------
1 | !SLIDE smbullets
2 | # Use Ruby to Start Making Awesome Command Line Applications
3 | ## Dave Copeland
4 | * [@davetron5000](http://www.twitter.com/davetron5000)
5 | * `davidcopeland (at) naildrivin5.com`
6 | * `david.copeland (at) livingsocial.com`
7 | * [naildrivin5.com/blog](http://www.naildrivin5.com/blog)
8 | * [www.awesomecommandlineapps.com](http://www.awesomecommandlineapps.com)
9 |
10 | !SLIDE commandline incremental
11 | # Who am I? #
12 |
13 | $ who am i
14 | Dave Copeland / @davetron5000
15 | $ ps
16 | Engineer at LivingSocial
17 |
18 | !SLIDE center
19 |
20 |
21 |
22 | !SLIDE commandline incremental
23 | # Who am I? #
24 |
25 | $ history
26 | 1986 c64 basic
27 | 1991 C # vi cursor keys didn't work
28 | 1995 Perl
29 | 1998 Java
30 | 2008 Ruby
31 | $ history | grep IDE
32 | 2010 history | grep IDE
33 |
34 | !SLIDE
35 | # Why care about command-line apps? #
36 |
37 | !SLIDE
38 | # An all too familiar tale...
39 |
40 | !SLIDE commandline incremental
41 | # Emergency! #
42 |
43 | $ vi one_off_script.sh
44 | $ ./one_off_script.sh -x /tmp/foo.csv > /top/magic.txt
45 | done.
46 | $ git add one_off_script.sh
47 | $ git commit -m 'automated stuff in time for launch'
48 |
49 | !SLIDE center
50 | # 6 Months Later... #
51 |
52 |
53 | !SLIDE center
54 | # 6 Months Later... #
55 |
56 |
57 | !SLIDE center
58 | # 6 Months Later... #
59 |
60 |
61 | !SLIDE center
62 | # Challenge Accepted
63 |
64 |
65 | !SLIDE commandline incremental
66 | # Challenge Accepted
67 | $ ./one_off_script.sh
68 | -bash: /tmp/intermediate.xml: not found
69 | $ ./one_off_script.sh help
70 | -bash: help: command not found
71 | $ ./one_off_script.sh --help
72 | done.
73 | $ ./one_off_script.sh /?
74 | ls: /? No such file or directory
75 |
76 | !SLIDE center
77 | ## vi ./one\_of\_script.sh
78 |
79 |
80 |
81 | !SLIDE bullets incremental
82 | # Why care about command-line apps? #
83 | * You *will* have to write them
84 | * And they *will* become someone's job
85 | * And you *will* be on the hook to fix them
86 | * Think about "future you"
87 |
88 | !SLIDE
89 | # Also, the command-line is an **infinitely flexible** way to **glue disparate systems** together and being able to write them makes you a **better, more versatile** developer
90 | !SLIDE bullets incremental
91 | # Make even your one-off scripts awesome #
92 |
93 | * No script is really a one-off
94 | * Be kind to "future you"
95 | * Ruby can make it easy
96 |
--------------------------------------------------------------------------------
/intro/book_cover.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/davetron5000/awesome-cli-ruby/71a4be7a94970527a3de1c705130ba1f7d3dd3e3/intro/book_cover.jpg
--------------------------------------------------------------------------------
/intro/challenge.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/davetron5000/awesome-cli-ruby/71a4be7a94970527a3de1c705130ba1f7d3dd3e3/intro/challenge.png
--------------------------------------------------------------------------------
/intro/comic.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/davetron5000/awesome-cli-ruby/71a4be7a94970527a3de1c705130ba1f7d3dd3e3/intro/comic.png
--------------------------------------------------------------------------------
/intro/ok.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/davetron5000/awesome-cli-ruby/71a4be7a94970527a3de1c705130ba1f7d3dd3e3/intro/ok.png
--------------------------------------------------------------------------------
/intro/rage1.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/davetron5000/awesome-cli-ruby/71a4be7a94970527a3de1c705130ba1f7d3dd3e3/intro/rage1.jpg
--------------------------------------------------------------------------------
/intro/rage2.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/davetron5000/awesome-cli-ruby/71a4be7a94970527a3de1c705130ba1f7d3dd3e3/intro/rage2.jpg
--------------------------------------------------------------------------------
/intro/rage3.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/davetron5000/awesome-cli-ruby/71a4be7a94970527a3de1c705130ba1f7d3dd3e3/intro/rage3.jpg
--------------------------------------------------------------------------------
/make_awesome/01_making_awesome.md:
--------------------------------------------------------------------------------
1 | !SLIDE subsection
2 | # Why Ruby?
3 |
4 | !SLIDE bullets incremental
5 | # Ruby, The Language
6 | * High-level abstractions
7 | * Still close to the metal (e.g. `FileUtils`)
8 | * Fast (no heavyweight VM to start up)
9 | * Simple packaging/distribution with RubyGems
10 |
11 | !SLIDE bullets incremental
12 | # Ruby, The Ecosystem
13 | * CLI is part of the culture
14 | * Great open-source gems for command-line
15 | * Great open-source gems for everything else
16 |
17 | !SLIDE subsection
18 | # Give me something I can use
19 |
20 | !SLIDE bullets incremental
21 | # Big sign of un-awesome
22 | * Crappy user interface
23 |
24 |
--------------------------------------------------------------------------------
/make_awesome/03_bad_ui.md:
--------------------------------------------------------------------------------
1 | !SLIDE
2 | # Poor User Interface
3 | ## Simple Apps
4 |
5 | @@@Ruby
6 |
7 | if ARGV[0] == '-f'
8 | filename = ARGV[1]
9 | end
10 |
11 | !SLIDE small
12 | # Poor User Interface
13 | ## Command-suite
14 |
15 | @@@ Ruby
16 | command = ARGV.shift
17 |
18 | case command
19 | when 'create'
20 | ShowOffUtils.create
21 | when 'heroku'
22 | ShowOffUtils.heroku
23 | when 'serve'
24 | ShowOff.run! :host => 'localhost', :port => 9090
25 | when 'static'
26 | ShowOff.do_static(ARGV)
27 | else
28 | ShowOffUtils.help
29 | end
30 |
31 | !SLIDE subsection
32 | # If you manipulate `ARGV`, you're doing it wrong
33 |
34 | !SLIDE bullets incremental
35 | # Poor User Interface
36 | * Hard to maintain & enhance
37 | * Hard for _others_ to maintain & enhance
38 | * *More* work than using libraries
39 |
40 |
--------------------------------------------------------------------------------
/make_awesome/04_option_parser.md:
--------------------------------------------------------------------------------
1 | !SLIDE small
2 | # Simple Apps
3 | ## `OptionParser`
4 |
5 | @@@ Ruby
6 | require 'optparse'
7 |
8 | options = {}
9 | opts = OptionParser.new do |opts|
10 | executable_name = File.split($0)[1]
11 | opts.banner = <<-EOS
12 | Jekyll is a static site generator
13 |
14 | Usage: #{executable_name} [options] args...
15 | EOS
16 |
17 | # option specifications go here
18 |
19 | end
20 | opts.parse!
21 |
22 | !SLIDE
23 | # OptionParser
24 | ## Parsing switches
25 |
26 | @@@ Ruby
27 | opts.on("--auto", "Auto-regenerate") do
28 | options['auto'] = true
29 | end
30 |
31 | !SLIDE small
32 | # OptionParser
33 | ## Negatable switches
34 |
35 | @@@ Ruby
36 | opts.on("--[no-]auto", "Auto-regenerate") do |auto|
37 | options['auto'] = auto
38 | end
39 |
40 | !SLIDE smaller
41 | # OptionParser
42 | ## Parsing flags
43 |
44 | @@@ Ruby
45 | opts.on("-s","--server PORT",
46 | "Start web server on PORT") do |port|
47 |
48 | # Do some sanity checking
49 | if port && port.to_i < 1000
50 | raise "Port must be >= 1000"
51 | end
52 |
53 | options['server_port'] = port.to_i
54 | end
55 |
56 | !SLIDE smaller
57 | # OptionParser
58 | ## Awesome Validation
59 |
60 | @@@ Ruby
61 | opts.on("--ip IP",
62 | /^\d+\.\d+\.\d+\.\d+$/,
63 | "IP address to bind to") do |ip|
64 | options['ip'] = ip # <- matches the regex
65 | end
66 |
67 | !SLIDE commandline small incremental
68 | # OptionParser
69 | ## Awesome Help
70 | $ awesome_app -h
71 | My awesome app is awesome
72 |
73 | Usage: awesome_app [options] args...
74 |
75 | --[no-]auto Auto-regenerate
76 | -s, --server PORT Start web server (def 4000)
77 | --ip IP IP address to bind to
78 | $ awesome_app --help
79 | # same thing
80 |
81 | !SLIDE bullets incremental
82 | # `OptionParser`
83 | * Easy for others to modify, too
84 | * No excuse, really
85 |
--------------------------------------------------------------------------------
/make_awesome/05_gli.md:
--------------------------------------------------------------------------------
1 | !SLIDE bullets incremental
2 | # What about command-suite?
3 | * `OptionParser` not well suited
4 | * A few other options
5 |
6 | !SLIDE bullets incremental
7 | # `GLI`
8 | * Tailor-made for command-suite
9 | * Make it easy for a polished UI
10 | * Easy to get started
11 |
12 | !SLIDE commandline incremental
13 |
14 | $ gem install gli
15 | Successfully installed gli
16 | $ gli init todo new list complete
17 | Creating dir ./todo/lib...
18 | Creating dir ./todo/bin...
19 | Creating dir ./todo/test...
20 | Created ./todo/bin/todo
21 | $ cd todo ; ls
22 | Gemfile README.rdoc Rakefile
23 | bin/ lib/ test/
24 | todo.gemspec todo.rdoc
25 |
26 | !SLIDE commandline small incremental
27 | $ bin/todo
28 | usage: todo [global options] command [command options]
29 |
30 | Version: 0.0.1
31 |
32 | Global Options:
33 | -f, --flagname=The name of the argument - Describe some flag here
34 | (default: the default)
35 | -s, --switch - Describe some switch here
36 |
37 | Commands:
38 | complete - Describe complete here
39 | help - Shows list of commands or help for one command
40 | list - Describe list here
41 | new - Describe new here
42 | $ bin/todo help list
43 | list
44 | Describe list here
45 |
46 | !SLIDE bullets incremental
47 | # What did we just get?
48 | * Command and option parsing
49 | * Complex help formatting
50 | * Boilerplate gem-ified project
51 |
52 | !SLIDE small
53 | # Make UI
54 |
55 | @@@Ruby
56 | desc 'location of the todo file'
57 | arg_name 'todo_file'
58 | default_value '~/.todo.txt'
59 | flag :f
60 |
61 | desc 'List all todo items'
62 | command :list do |c|
63 | c.desc 'List in long form'
64 | c.switch :l
65 |
66 | c.desc 'Show all items, even completed'
67 | c.switch [:a,:all]
68 |
69 | c.desc 'Specify sort order'
70 | c.arg_name '[date|name|completed]'
71 | c.flag [:s,:sort]
72 | c.action do |global_options,options,args|
73 | # Logic goes here
74 | end
75 | end
76 |
77 | !SLIDE commandline small incremental
78 | # And now...
79 | $ bin/todo help
80 | usage: todo command [command options]
81 |
82 | Global Options:
83 | -f - location of the todo file (default ~/.todo.txt)
84 |
85 | Version: 0.0.1
86 |
87 | Commands:
88 | complete - Complete one or more items
89 | help - Shows list of commands or help for one command
90 | list - List all todo items
91 | new - Create a new todo item
92 | $ bin/todo help list
93 | list [command options]
94 | List all todo items
95 |
96 | Command Options:
97 | -a, --all - Show all items, even
98 | completed ones
99 | -l - List in long form
100 | -s, --sort=[date|name|completed] - Specify sort order
101 |
102 |
103 | !SLIDE bullets
104 | # Many other cool features, too
105 | * [github.com/davetron5000/gli](http://github.com/davetron5000/gli)
106 |
--------------------------------------------------------------------------------
/make_awesome/06_summary.md:
--------------------------------------------------------------------------------
1 | !SLIDE bullets incremental
2 | # `OptionParser` and `GLI`
3 | * Dead-simple, polished UI
4 | * Spend time on your app, not formatting help text
5 | * Easily maintain documentation
6 |
7 | !SLIDE subsection
8 | # Other CLI Gems
9 |
--------------------------------------------------------------------------------
/make_awesome/07_other.md:
--------------------------------------------------------------------------------
1 | !SLIDE smbullets incremental
2 | # CLI-parsing tools
3 | * `OptionParser` - builtin
4 | * [`GLI`](http://github.com/davetron5000/gli/) - mega-easy command-suite
5 | * [`thor`](http://github.com/wycats/thor) - command-suite
6 | * [`trollop`](http://trollop.rubyforge.org/) - simple and command-suite
7 | * [`methadone`](http://github.com/davetron5000/methadone/) - simple + bootstrapping
8 |
9 | !SLIDE smbullets incremental
10 | # User interaction
11 | * `readline` - (builtin) command-line history/editing
12 | * [`highline`](http://highline.rubyforge.org/) - get user I/O cleanly
13 | * [`terminal-tables`](http://github.com/visionmedia/terminal-table) - make formatted ASCII tables
14 | * [`rainbow`](http://github.com/sickill/rainbow) - color your output
15 |
16 | !SLIDE bullets incremental
17 | # Testing & Documentation
18 | * [`aruba`](https://github.com/aslakhellesoy/aruba) - Cuke-style command-line tests
19 | * [`gem-man`](https://github.com/defunkt/gem-man) - Install man pages with your gem
20 | * [`ronn`](http://rtomayko.github.com/ronn/) - Author man pages in markdown
21 |
22 | !SLIDE bullets incremental
23 | # In conclusion...
24 | * Making awesome is *easy*
25 | * Ruby makes it simple
26 | * Tools like GLI and OptionParser make it fast
27 | * "Future you" thanks you
28 |
29 | !SLIDE subsection
30 | # Am I missing something?
31 |
32 | !SLIDE subsection
33 | # or (gasp) wrong?
34 |
35 | !SLIDE center
36 |
37 |
38 |
39 | !SLIDE smbullets
40 | # Thanks!
41 | * [@davetron5000](http://www.twitter.com/davetron5000)
42 | * [www.naildrivin5.com/blog](http://www.naildrivin5.com/blog)
43 | * [www.awesomecommandlineapps.com](http://www.awesomecommandlineapps.com)
44 | * Slides on Github - [http://bit.ly/cli-gh](http://bit.ly/cli-gh)
45 | * Slides on Heroku - [http://bit.ly/cli-slides](http://bit.ly/cli-slides)
46 | * Rate this talk at [http://spkr8.com/t/8839](http://spkr8.com/t/8839)
47 |
--------------------------------------------------------------------------------
/make_awesome/zz_bad_system.md:
--------------------------------------------------------------------------------
1 | !SLIDE
2 | # Poor subprocess management
3 |
4 | @@@Ruby
5 | include FileUtils
6 |
7 | date = Time.now.to_s
8 | filename = "#{date}_foo_db.sql"
9 | tmp = "#{filename}.tmp"
10 |
11 | %x[mysqldump foo_db > #{tmp}]
12 |
13 | mv(tmp,filename)
14 |
15 | %x[gzip #{filename}]
16 |
17 |
18 |
19 | !SLIDE bullets incremental
20 | # How you should do it
21 | * *Check exit codes* - plays well!
22 | * *Log the command* - helpful!
23 | * *Capture the output* - helpful!
24 | * Think of "future you"
25 |
26 | !SLIDE smaller
27 | # Use `open3`
28 |
29 | @@@Ruby
30 | command = "/full/path/to/some_external_command.sh"
31 | stdout,stderr,status = Open3.capture3(command)
32 | STDERR.puts(stderr) # Their stderr is our stderr
33 |
34 | if status.success?
35 | stdout.split(/\n/).each do |line|
36 | # Do our work
37 | end
38 | true
39 | else
40 | STDERR.puts("Problem running #{command}")
41 | false
42 | end
43 |
44 | !SLIDE smaller
45 | # Throw it in a method
46 |
47 | @@@Ruby
48 | include FileUtils
49 |
50 | def sh(command)
51 | # Stuff from previous slide...
52 | end
53 |
54 | date = Time.now.to_s
55 | filename = "#{date}_foo_db.sql"
56 | tmp = "#{filename}.tmp"
57 | if sh("mysqldump foo_db > #{tmp}")
58 | if mv(tmp,filename)
59 | if sh("gzip #{filename}")
60 | exit 0
61 | else
62 | exit 1
63 | end
64 | else
65 | rm(tmp)
66 | exit 2
67 | end
68 | else
69 | rm(tmp)
70 | exit 3
71 | end
72 |
73 | !SLIDE bullets incremental
74 | # Awesome subprocess management
75 | * Customize it...
76 | * ...put it in a gem...
77 | * ...and use it instead of `system` or `%x[]`
78 | * External calls are now bulletproof
79 | * And it's the same LOC
80 |
81 |
--------------------------------------------------------------------------------
/opower.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/davetron5000/awesome-cli-ruby/71a4be7a94970527a3de1c705130ba1f7d3dd3e3/opower.png
--------------------------------------------------------------------------------
/showoff.json:
--------------------------------------------------------------------------------
1 | [{"section":"intro"},{"section":"what_is_awesome"},{"section":"make_awesome"}]
2 |
--------------------------------------------------------------------------------
/styles.css:
--------------------------------------------------------------------------------
1 | /*
2 | * LivingSocial Colors:
3 | *
4 | * Primary Palette:
5 | *
6 | * honeycomb - #e9ba2a;
7 | * clementine - #f0812b;
8 | * slushie - #5fb8dd;
9 | * frosting - #ea0b8c;
10 | *
11 | * Secondary Palette:
12 | *
13 | * aloe - #50886b;
14 | * berry - #508395;
15 | * wasabi - #9eae3d;
16 | * grape - #92278f;
17 | * spice - #eb3f3c;
18 | * wine - #832e2f;
19 | *
20 | */
21 | body, .slide, h1, h2, h3, h4, h5, p, div {
22 | color: black;
23 | }
24 |
25 | h1 {
26 | font-family: Arial rounded mt bold, Helvetica, Arial, sans-serif;
27 | }
28 |
29 | h2, h3, h4, h5 {
30 | font-family: Georgia, Times, serif;
31 | font-style: italic;
32 | }
33 |
34 | p, div, li {
35 | font-family: Helvetica, Arial, sans-serif;
36 | }
37 |
38 | body {
39 | background: #e9ba2a;
40 | }
41 |
42 | div.subsection h1 {
43 | background: #f0812b;
44 | color: white;
45 | padding-top: 20px;
46 | padding-bottom: 20px;
47 | }
48 |
49 | blockquote {
50 | margin: 20px;
51 | padding: 20px;
52 | text-indent: 40px;
53 | border: solid thin;
54 | background: #832e2f;
55 | -webkit-border-radius: 10px;
56 | -moz-border-radius: 10px;
57 | border-radius: 10px;
58 | }
59 | blockquote p em {
60 | color: white;
61 | font-size: 200%;
62 | line-height: 40px;
63 | }
64 | .slide {
65 | /*
66 | * background-image: url("opower.png");
67 | */
68 | background-repeat: no-repeat;
69 | background-attachment:fixed;
70 | background-position: 83% 94%;
71 | }
72 |
73 | a:hover, a:visited, a {
74 | color: #508395;
75 | }
76 |
77 | code.result {
78 | font-weight: bold;
79 | color: #262626;
80 | }
81 |
82 | /*
83 | * orig Opower LivingSocial
84 | * color: black black black;
85 | * color: blue #0088CE #508395;
86 | * color: brown #FF5800 #e9ba2a;
87 | * color: cyan #69C8F8 #5fb8dd;
88 | * color: darkblue #005293 #508395;
89 | * color: darkgreen #7AB800 #50886b;
90 | * color: darkred #A30050 #832e2f;
91 | * color: orange #FF5800 #f0812b;
92 | * color: pink #B1059D #ea0b8c;
93 | * color: purple #B1059D #832e2f;
94 | * color: red #A30050 #eb3f3c;
95 | * color: teal #D9E506 #92278f;
96 | */
97 |
98 | pre.sh_sourceCode {
99 | background: transparent;
100 | }
101 | pre.sh_sourceCode .sh_keyword { color: #508395; font-weight: bold; } /* language keywords */
102 | pre.sh_sourceCode .sh_type { color: #50886b; } /* basic types */
103 | pre.sh_sourceCode .sh_usertype { color: #92278f; } /* user defined types */
104 | pre.sh_sourceCode .sh_string { color: #832e2f; font-family: monospace; } /* strings and chars */
105 | pre.sh_sourceCode .sh_regexp { color: #e9ba2a; font-family: monospace; } /* regular expressions */
106 | pre.sh_sourceCode .sh_specialchar { color: #ea0b8c; font-family: monospace; } /* e.g., \n, \t, \\ */
107 | pre.sh_sourceCode .sh_comment { color: #e9ba2a; font-style: italic; } /* comments */
108 | pre.sh_sourceCode .sh_number { color: #ea0b8c; } /* literal numbers */
109 | pre.sh_sourceCode .sh_preproc { color: #508395; font-weight: bold; } /* e.g., #include, import */
110 | pre.sh_sourceCode .sh_symbol { color: #832e2f; } /* */
111 | pre.sh_sourceCode .sh_function { color: black; font-weight: bold; } /* function calls and declarations */
112 | pre.sh_sourceCode .sh_cbracket { color: #832e2f; } /* block brackets (e.g., {, }) */
113 | pre.sh_sourceCode .sh_todo { font-weight: bold; background-color: #5fb8dd; } /* TODO and FIXME */
114 |
115 | /* Predefined variables and functions (for instance glsl) */
116 | pre.sh_sourceCode .sh_predef_var { color: #508395; }
117 | pre.sh_sourceCode .sh_predef_func { color: #508395; font-weight: bold; }
118 |
119 | /* for OOP */
120 | pre.sh_sourceCode .sh_classname { color: #92278f; }
121 |
122 |
123 | /* other */
124 | pre.sh_sourceCode .sh_section { color: black; font-weight: bold; }
125 | pre.sh_sourceCode .sh_paren { color: #832e2f; }
126 | pre.sh_sourceCode .sh_attribute { color: #50886b; }
127 |
128 |
--------------------------------------------------------------------------------
/what_is_awesome/01_awesome_defined.md:
--------------------------------------------------------------------------------
1 | !SLIDE bullets incremental
2 | # Awesome Defined #
3 | * Act Like a First Class App
4 | * Play Well With Others
5 | * Be Helpful
6 |
7 |
--------------------------------------------------------------------------------
/what_is_awesome/02_first_class.md:
--------------------------------------------------------------------------------
1 | !SLIDE bullets incremental subsection
2 | # (1) Act First Class #
3 |
4 | !SLIDE bullets incremental
5 | # Act First Class #
6 | * It's not a "script"
7 | * ...it's an _application_
8 | * Approach it as you would first-class application
9 |
10 | !SLIDE bullets incremental
11 | # How?
12 | * Decide to have a _real_ UI
13 | * Decide to use good design, write documentation, and use a real distribution system
14 | * Decide to *care*
15 | * If you plan ahead, this stuff isn't that hard
16 |
--------------------------------------------------------------------------------
/what_is_awesome/03_play_well.md:
--------------------------------------------------------------------------------
1 | !SLIDE subsection
2 | # (2) Play Well With Others
3 |
4 | !SLIDE bullets incremental
5 | # The UNIX Way
6 | ## [http://www.faqs.org/docs/artu/ch01s06.html](http://www.faqs.org/docs/artu/ch01s06.html) ##
7 | > _(ii) Expect the output of every program to become the input to another, as yet unknown, program. Don't clutter output with extraneous information. Avoid stringently columnar or binary input formats. Don't insist on interactive input._
8 |
9 | !SLIDE bullets incremental
10 | # The UNIX Way ##
11 | * grepable (One "record" per line)
12 | * cutable (delimited "fields")
13 | * exit codes! (0 for success, nonzero for failure)
14 | * messaging (stderr) vs. output (stdout)
15 |
16 | !SLIDE commandline incremental smaller
17 | # Example - Plays Horribly With Others #
18 |
19 | $ mvn test -Dtest=TestHeatingComparison
20 | [INFO] Scanning for projects...
21 | [INFO] ------------------------------------------------------------------------
22 | [INFO] Building Standalone Core Library
23 | [INFO] task-segment: [test]
24 | [INFO] ------------------------------------------------------------------------
25 | [INFO] [resources:copy-resources {execution: default}]
26 | [INFO] Using 'UTF-8' encoding to copy filtered resources.
27 | [INFO] skip non existing resourceDirectory /Users/davec/Projects/opower/core/null/null/trunk/src/main/resources/webclientconfig/clients/null/assets
28 | [INFO] [svn-revision-number:revision {execution: default}]
29 | [INFO] inspecting /Users/davec/Projects/opower/core
30 | [INFO] [resources:resources {execution: default-resources}]
31 | [INFO] Using 'UTF-8' encoding to copy filtered resources.
32 | [INFO] Copying 9 resources
33 | [INFO] Copying 1 resource
34 | [INFO] Copying 332 resources to patches/core
35 | [INFO] Copying 23 resources to postpatches/core
36 | [INFO] [compiler:compile {execution: default-compile}]
37 | [INFO] Compiling 16 source files to /Users/davec/Projects/opower/core/target/classes
38 | [INFO] [checkstyle:checkstyle {execution: checkstyle}]
39 | [INFO] Starting audit...
40 | Audit done.
41 |
42 | [INFO] Setting property: classpath.resource.loader.class => 'org.codehaus.plexus.velocity.ContextClassLoaderResourceLoader'.
43 | [INFO] Setting property: velocimacro.messages.on => 'false'.
44 | [INFO] Setting property: resource.loader => 'classpath'.
45 | [INFO] Setting property: resource.manager.logwhenfound => 'false'.
46 | [INFO] **************************************************************
47 | [INFO] Starting Jakarta Velocity v1.4
48 | [INFO] RuntimeInstance initializing.
49 | [INFO] Default Properties File: org/apache/velocity/runtime/defaults/velocity.properties
50 | [INFO] Default ResourceManager initializing. (class org.apache.velocity.runtime.resource.ResourceManagerImpl)
51 | [INFO] Resource Loader Instantiated: org.codehaus.plexus.velocity.ContextClassLoaderResourceLoader
52 |
53 | !SLIDE commandline smaller
54 | # Plays Horribly With Others (con't) #
55 |
56 | $ mvn test -Dtest=TestHeatingComparison # con't
57 | [INFO] ClasspathResourceLoader : initialization starting.
58 | [INFO] ClasspathResourceLoader : initialization complete.
59 | [INFO] ResourceCache : initialized. (class org.apache.velocity.runtime.resource.ResourceCacheImpl)
60 | [INFO] Default ResourceManager initialization complete.
61 | [INFO] Loaded System Directive: org.apache.velocity.runtime.directive.Literal
62 | [INFO] Loaded System Directive: org.apache.velocity.runtime.directive.Macro
63 | [INFO] Loaded System Directive: org.apache.velocity.runtime.directive.Parse
64 | [INFO] Loaded System Directive: org.apache.velocity.runtime.directive.Include
65 | [INFO] Loaded System Directive: org.apache.velocity.runtime.directive.Foreach
66 | [INFO] Created: 20 parsers.
67 | [INFO] Velocimacro : initialization starting.
68 | [INFO] Velocimacro : adding VMs from VM library template : VM_global_library.vm
69 | [ERROR] ResourceManager : unable to find resource 'VM_global_library.vm' in any resource loader.
70 | [INFO] Velocimacro : error using VM library template VM_global_library.vm : org.apache.velocity.exception.ResourceNotFoundException: Unable to find resource 'VM_global_library.vm'
71 | [INFO] Velocimacro : VM library template macro registration complete.
72 | [INFO] Velocimacro : allowInline = true : VMs can be defined inline in templates
73 | [INFO] Velocimacro : allowInlineToOverride = false : VMs defined inline may NOT replace previous VM definitions
74 | [INFO] Velocimacro : allowInlineLocal = false : VMs defined inline will be global in scope if allowed.
75 | [INFO] Velocimacro : initialization complete.
76 | [INFO] Velocity successfully started.
77 | [INFO] [resources:testResources {execution: default-testResources}]
78 | [INFO] Using 'UTF-8' encoding to copy filtered resources.
79 | [INFO] Copying 501 resources
80 | [INFO] Copying 9 resources
81 | [INFO] [compiler:testCompile {execution: default-testCompile}]
82 | [INFO] Compiling 1 source file to /Users/davec/Projects/opower/core/target/test-classes
83 | [INFO] [surefire:test {execution: default-test}]
84 |
85 | !SLIDE commandline smaller
86 | # Plays Horribly With Others (con't) #
87 |
88 | $ mvn test -Dtest=TestHeatingComparison # still con't
89 | [INFO] Surefire report directory: /Users/davec/Projects/opower/core/target/surefire-reports
90 |
91 | -------------------------------------------------------
92 | T E S T S
93 | -------------------------------------------------------
94 | Running poscore.model.TestHeatingComparison
95 | Tests run: 6, Failures: 1, Errors: 0, Skipped: 0, Time elapsed: 0.133 sec <<< FAILURE!
96 |
97 | Results :
98 |
99 | Failed tests:
100 | testSetters(poscore.model.TestHeatingComparison)
101 |
102 | Tests run: 6, Failures: 1, Errors: 0, Skipped: 0
103 |
104 | [INFO] ------------------------------------------------------------------------
105 | [ERROR] BUILD FAILURE
106 | [INFO] ------------------------------------------------------------------------
107 | [INFO] There are test failures.
108 |
109 | Please refer to /Users/davec/Projects/opower/core/target/surefire-reports for the individual test results.
110 | [INFO] ------------------------------------------------------------------------
111 | [INFO] For more information, run Maven with the -e switch
112 | [INFO] ------------------------------------------------------------------------
113 | [INFO] Total time: 13 seconds
114 | [INFO] Finished at: Fri May 07 13:50:01 EDT 2010
115 | [INFO] Final Memory: 54M/527M
116 | [INFO] ------------------------------------------------------------------------
117 |
118 | $ echo $?
119 | 0
120 |
121 | !SLIDE commandline incremental
122 | # Example - Plays Well With Others #
123 |
124 | $ svn stat
125 | M Rakefile
126 | C README.rdoc
127 | ? bin/my_cmd
128 | C test/tc_cmd.rb
129 | $ vi `svn stat | grep ^C | awk '{print $2}'`
130 | # Now editing all files with conflicts
131 | $ svn stat | grep ^C | awk '{print $2}' | xargs svn resolved
132 | Resolved conflicted state of 'README.rdoc'
133 | Resolved conflicted state of 'test/tc_cmd.rb'
134 |
135 |
--------------------------------------------------------------------------------
/what_is_awesome/04_be_helpful.md:
--------------------------------------------------------------------------------
1 | !SLIDE bullets incremental subsection
2 | # (3) Be helpful
3 |
4 | !SLIDE bullets incremental
5 | # Be helpful
6 | * Help users know how to use and understand your app
7 | * Don't punish on user error - be helpful
8 |
9 | !SLIDE commandline smaller incremental
10 | # Example - Not Helpful
11 |
12 | $ latex
13 | This is pdfeTeX, Version 3.141592-1.21a-2.2 (Web2C 7.5.4)
14 | **
15 | ^C
16 | $ latex help
17 | This is pdfeTeX, Version 3.141592-1.21a-2.2 (Web2C 7.5.4)
18 | entering extended mode
19 | ! I can't find file `help'.
20 | <*> help
21 |
22 | Please type another input file name:^C
23 | ! I can't find file `help'.
24 | <*> help
25 |
26 | Please type another input file name: ^D
27 | ! Emergency stop.
28 | <*> help
29 |
30 | No pages of output.
31 | Transcript written on texput.log.
32 |
33 | !SLIDE commandline small incremental
34 | # Helpful
35 | $ git
36 | usage: git [--version] [--exec-path[=GIT_EXEC_PATH]] [--html-path]
37 | [-p|--paginate|--no-pager]
38 | [--bare] [--git-dir=GIT_DIR] [--work-tree=GIT_WORK_TREE]
39 | [--help] COMMAND [ARGS]
40 |
41 | The most commonly used git commands are:
42 | add Add file contents to the index
43 | bisect Find by binary search the change that introduced a bug
44 |
45 | tag Create, list, delete or verify a tag object signed with GPG
46 |
47 | See 'git help COMMAND' for more information on a specific command.
48 |
49 | !SLIDE bullets incremental
50 | # Two classes of apps
51 | * *Simple* - does-one-thing-UNIX-style app
52 | * Think `ls` or `grep`
53 | * *Command Suite* - complex, does a lot
54 | * Think `git` or `gem`
55 |
56 | !SLIDE bullets incremental
57 | # Be Helpful #
58 | ## Simple ##
59 | ### `my_cmd`
60 |
61 | * Don't do anything destructive by default
62 | * Show a brief help statement
63 |
64 | !SLIDE bullets incremental
65 | # Be Helpful #
66 | ## Simple ##
67 | ### `my_cmd -h`
68 |
69 | * Show a fuller help statement
70 | * Also support `--help`
71 |
72 | !SLIDE bullets incremental
73 | # Be Helpful #
74 | ## Command Suite ##
75 | ### `my_cmd`
76 |
77 | * List available commands
78 | * List globally-applicable options
79 | * The command `help` should do the same (e.g. `my_cmd help`)
80 |
81 | !SLIDE bullets incremental
82 | # Be Helpful #
83 | ## Command Suite ##
84 | ### `my_cmd help command_name`
85 |
86 | * help on `command_name`
87 | * i.e. what it does
88 | * and the options available
89 |
90 | !SLIDE bullets incremental
91 | # Oh, and useful error messages
92 | * "undefined method `[]' for nil:NilClass (NoMethodError)"
93 | * Ruby allows *any number* of `if` statements
94 |
--------------------------------------------------------------------------------
/what_is_awesome/cuke_fail.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/davetron5000/awesome-cli-ruby/71a4be7a94970527a3de1c705130ba1f7d3dd3e3/what_is_awesome/cuke_fail.png
--------------------------------------------------------------------------------
/what_is_awesome/cuke_pass.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/davetron5000/awesome-cli-ruby/71a4be7a94970527a3de1c705130ba1f7d3dd3e3/what_is_awesome/cuke_pass.png
--------------------------------------------------------------------------------