cl 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/Gemfile +3 -0
- data/Gemfile.lock +25 -0
- data/MIT_LICENSE.md +21 -0
- data/README.md +23 -0
- data/lib/cli.rb +19 -0
- data/lib/cli/cmd.rb +28 -0
- data/lib/cli/cmds.rb +28 -0
- data/lib/cli/format/cmd.rb +31 -0
- data/lib/cli/format/list.rb +22 -0
- data/lib/cli/format/table.rb +19 -0
- data/lib/cli/format/usage.rb +20 -0
- data/lib/cli/help.rb +31 -0
- data/lib/cli/options.rb +11 -0
- data/lib/cli/registry.rb +53 -0
- data/lib/cli/runner.rb +20 -0
- data/lib/cli/version.rb +3 -0
- metadata +59 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 2f86887c16aed295c0207a4c5005decf8fd1cc05
|
4
|
+
data.tar.gz: 12260c6e0abc90a6b2df31fd3ce1797189953539
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: b4277518e42daa3e8f19bf612ffdae68c6244e28a043915e1842fdc28b200493e5fbe41f821b2040443f861e7e8cafae0d705b08d592b7cfd2dcc51cc719a73e
|
7
|
+
data.tar.gz: 54a224126510e271f4847ffc6a089cb130af5ac00e0c50c8d001e1d183f8c5d2ebd8c3dd48b56742764503c7379ef4bf06333994d195b4f82496c81d956e475e
|
data/Gemfile
ADDED
data/Gemfile.lock
ADDED
@@ -0,0 +1,25 @@
|
|
1
|
+
GEM
|
2
|
+
specs:
|
3
|
+
diff-lcs (1.3)
|
4
|
+
rspec (3.5.0)
|
5
|
+
rspec-core (~> 3.5.0)
|
6
|
+
rspec-expectations (~> 3.5.0)
|
7
|
+
rspec-mocks (~> 3.5.0)
|
8
|
+
rspec-core (3.5.4)
|
9
|
+
rspec-support (~> 3.5.0)
|
10
|
+
rspec-expectations (3.5.0)
|
11
|
+
diff-lcs (>= 1.2.0, < 2.0)
|
12
|
+
rspec-support (~> 3.5.0)
|
13
|
+
rspec-mocks (3.5.0)
|
14
|
+
diff-lcs (>= 1.2.0, < 2.0)
|
15
|
+
rspec-support (~> 3.5.0)
|
16
|
+
rspec-support (3.5.0)
|
17
|
+
|
18
|
+
PLATFORMS
|
19
|
+
ruby
|
20
|
+
|
21
|
+
DEPENDENCIES
|
22
|
+
rspec
|
23
|
+
|
24
|
+
BUNDLED WITH
|
25
|
+
1.14.5
|
data/MIT_LICENSE.md
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
# MIT LICENSE
|
2
|
+
|
3
|
+
Copyright (c) 2017 Sven Fuchs <me@svenfuchs.com>
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
7
|
+
in the Software without restriction, including without limitation the rights
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
10
|
+
furnished to do so, subject to the following conditions:
|
11
|
+
|
12
|
+
The above copyright notice and this permission notice shall be included in
|
13
|
+
all copies or substantial portions of the Software.
|
14
|
+
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
21
|
+
THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,23 @@
|
|
1
|
+
# CLI
|
2
|
+
|
3
|
+
This library wraps Ruby's `OptionParser` in order to make it easier to use it in an object oriented context.
|
4
|
+
|
5
|
+
## Usage
|
6
|
+
|
7
|
+
```
|
8
|
+
module Owners
|
9
|
+
class Add < Struct.new(:args, :opts)
|
10
|
+
include Cli::Cmd
|
11
|
+
|
12
|
+
register 'owners:add'
|
13
|
+
|
14
|
+
purpose 'Add one or more owners to an existing owner group'
|
15
|
+
|
16
|
+
args :owners
|
17
|
+
|
18
|
+
on '-t', '--to TO', 'An owner in an existing group' do |value|
|
19
|
+
opts[:to] = value
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
```
|
data/lib/cli.rb
ADDED
@@ -0,0 +1,19 @@
|
|
1
|
+
require 'cli/cmd'
|
2
|
+
require 'cli/help'
|
3
|
+
require 'cli/runner'
|
4
|
+
|
5
|
+
module Cli
|
6
|
+
def included(const)
|
7
|
+
const.send(:include, Cmd)
|
8
|
+
end
|
9
|
+
|
10
|
+
def run(*args)
|
11
|
+
Runner.new(*args).run
|
12
|
+
end
|
13
|
+
|
14
|
+
def help
|
15
|
+
Runner.new(:help).run
|
16
|
+
end
|
17
|
+
|
18
|
+
extend self
|
19
|
+
end
|
data/lib/cli/cmd.rb
ADDED
@@ -0,0 +1,28 @@
|
|
1
|
+
require 'cli/registry'
|
2
|
+
|
3
|
+
module Cli
|
4
|
+
module Cmd
|
5
|
+
def self.included(const)
|
6
|
+
const.send :include, Registry
|
7
|
+
const.send :extend, ClassMethods
|
8
|
+
end
|
9
|
+
|
10
|
+
module ClassMethods
|
11
|
+
def args(*args)
|
12
|
+
args.any? ? @args = args : @args ||= []
|
13
|
+
end
|
14
|
+
|
15
|
+
def purpose(purpose = nil)
|
16
|
+
purpose ? @purpose = purpose : @purpose
|
17
|
+
end
|
18
|
+
|
19
|
+
def on(*args, &block)
|
20
|
+
opts << [args, block]
|
21
|
+
end
|
22
|
+
|
23
|
+
def opts
|
24
|
+
@opts ||= superclass.respond_to?(:opts) ? superclass.opts : []
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
data/lib/cli/cmds.rb
ADDED
@@ -0,0 +1,28 @@
|
|
1
|
+
require 'cli/options'
|
2
|
+
|
3
|
+
module Cli
|
4
|
+
class Cmds < Struct.new(:args)
|
5
|
+
def lookup
|
6
|
+
cmd || abort("Unknown command: #{args.join(' ')}")
|
7
|
+
opts = Options.new(cmd.opts, args).opts
|
8
|
+
[cmd, args - cmds, opts]
|
9
|
+
end
|
10
|
+
|
11
|
+
private
|
12
|
+
|
13
|
+
def cmds
|
14
|
+
name = cmd.registry_key.to_s
|
15
|
+
args.take_while do |arg|
|
16
|
+
name = name.sub(/#{arg}(:|$)/, '') if name =~ /#{arg}(:|$)/
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
def cmd
|
21
|
+
@cmd ||= keys.map { |key| Cli[key] }.compact.last
|
22
|
+
end
|
23
|
+
|
24
|
+
def keys
|
25
|
+
@keys ||= args.inject([]) { |keys, key| keys << [keys.last, key].compact.join(':') }
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
require 'cli/format/table'
|
2
|
+
require 'cli/format/usage'
|
3
|
+
|
4
|
+
module Cli
|
5
|
+
class Format
|
6
|
+
class Cmd < Struct.new(:cmd)
|
7
|
+
def format
|
8
|
+
[banner, Table.new(opts).format].join("\n")
|
9
|
+
end
|
10
|
+
|
11
|
+
def banner
|
12
|
+
banner = []
|
13
|
+
banner << "#{cmd.purpose}\n" if cmd.purpose
|
14
|
+
banner << "Usage: #{Usage.new(cmd).format}\n"
|
15
|
+
banner
|
16
|
+
end
|
17
|
+
|
18
|
+
def opts
|
19
|
+
cmd.opts.map do |opts, block|
|
20
|
+
comment = opts.detect { |opt| !opt?(opt) }
|
21
|
+
opts = opts.select { |opt| opt?(opt) }
|
22
|
+
[opts.sort_by(&:size).join(' '), comment]
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
def opt?(str)
|
27
|
+
str.start_with?('-')
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
require 'cli/format/table'
|
2
|
+
require 'cli/format/usage'
|
3
|
+
|
4
|
+
module Cli
|
5
|
+
class Format
|
6
|
+
class List < Struct.new(:cmds)
|
7
|
+
HEAD = %(Type "#{$0} help COMMAND [SUBCOMMAND]" for more details:\n)
|
8
|
+
|
9
|
+
def format
|
10
|
+
[HEAD, Format::Table.new(list).format].join("\n")
|
11
|
+
end
|
12
|
+
|
13
|
+
def list
|
14
|
+
cmds.map { |cmd| format_cmd(cmd) }
|
15
|
+
end
|
16
|
+
|
17
|
+
def format_cmd(cmd)
|
18
|
+
["#{$0} #{Usage.new(cmd).format}", cmd.purpose]
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
module Cli
|
2
|
+
class Format
|
3
|
+
class Table < Struct.new(:data, :separator)
|
4
|
+
def format
|
5
|
+
rows.join("\n")
|
6
|
+
end
|
7
|
+
|
8
|
+
def rows
|
9
|
+
rows = data.map { |lft, rgt| [lft.ljust(width), rgt] }
|
10
|
+
rows = rows.map { |lft, rgt| "#{lft} #{"# #{rgt}" if rgt}".strip }
|
11
|
+
rows.map(&:strip)
|
12
|
+
end
|
13
|
+
|
14
|
+
def width
|
15
|
+
@width ||= data.map(&:first).max_by(&:size).size
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
module Cli
|
2
|
+
class Format
|
3
|
+
class Usage < Struct.new(:cmd)
|
4
|
+
def format
|
5
|
+
usage = [name]
|
6
|
+
usage += cmd.args.map { |arg| "[#{arg}]" }
|
7
|
+
usage << '[options]' if opts?
|
8
|
+
usage.join(' ')
|
9
|
+
end
|
10
|
+
|
11
|
+
def name
|
12
|
+
cmd.registry_key.to_s.gsub(':', ' ')
|
13
|
+
end
|
14
|
+
|
15
|
+
def opts?
|
16
|
+
cmd.opts.any?
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
data/lib/cli/help.rb
ADDED
@@ -0,0 +1,31 @@
|
|
1
|
+
require 'cli/format/cmd'
|
2
|
+
require 'cli/format/list'
|
3
|
+
|
4
|
+
module Cli
|
5
|
+
class Help < Struct.new(:args, :opts)
|
6
|
+
include Cli::Cmd
|
7
|
+
|
8
|
+
register :help
|
9
|
+
|
10
|
+
def run
|
11
|
+
puts help
|
12
|
+
end
|
13
|
+
|
14
|
+
def help
|
15
|
+
cmd ? Format::Cmd.new(cmd).format : Format::List.new(cmds).format
|
16
|
+
end
|
17
|
+
|
18
|
+
private
|
19
|
+
|
20
|
+
def cmds
|
21
|
+
cmds = Cli.cmds.reject { |cmd| cmd.registry_key == :help }
|
22
|
+
key = args.join(':') if args
|
23
|
+
cmds = cmds.select { |cmd| cmd.registry_key.to_s.start_with?(key) } if key
|
24
|
+
cmds
|
25
|
+
end
|
26
|
+
|
27
|
+
def cmd
|
28
|
+
args && Cli[args.join(':')]
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
data/lib/cli/options.rb
ADDED
data/lib/cli/registry.rb
ADDED
@@ -0,0 +1,53 @@
|
|
1
|
+
module Cli
|
2
|
+
class << self
|
3
|
+
def []=(key, object)
|
4
|
+
registry[key.to_sym] = object
|
5
|
+
end
|
6
|
+
|
7
|
+
def [](key)
|
8
|
+
key && registry[key.to_sym]
|
9
|
+
end
|
10
|
+
|
11
|
+
def cmds
|
12
|
+
registry.values
|
13
|
+
end
|
14
|
+
|
15
|
+
def registry
|
16
|
+
@registry ||= {}
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
module Registry
|
21
|
+
class << self
|
22
|
+
def included(const)
|
23
|
+
const.send(:extend, ClassMethods)
|
24
|
+
const.send(:include, InstanceMethods)
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
module ClassMethods
|
29
|
+
attr_reader :registry_key
|
30
|
+
|
31
|
+
def [](key)
|
32
|
+
Cli[key.to_sym]
|
33
|
+
end
|
34
|
+
|
35
|
+
def register(key)
|
36
|
+
Cli[key] = self
|
37
|
+
@registry_key = key.to_sym
|
38
|
+
end
|
39
|
+
|
40
|
+
def underscore(string)
|
41
|
+
string.gsub(/([A-Z]+)([A-Z][a-z])/,'\1_\2').
|
42
|
+
gsub(/([a-z\d])([A-Z])/,'\1_\2').
|
43
|
+
downcase
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
module InstanceMethods
|
48
|
+
def registry_key
|
49
|
+
self.class.registry_key
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
data/lib/cli/runner.rb
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
require 'cli/cmds'
|
2
|
+
|
3
|
+
module Cli
|
4
|
+
class Runner
|
5
|
+
attr_reader :const, :args, :opts
|
6
|
+
|
7
|
+
def initialize(*args)
|
8
|
+
args = args.flatten.map(&:to_s)
|
9
|
+
@const, @args, @opts = Cmds.new(args).lookup
|
10
|
+
end
|
11
|
+
|
12
|
+
def run
|
13
|
+
cmd.run
|
14
|
+
end
|
15
|
+
|
16
|
+
def cmd
|
17
|
+
const.new(args, opts)
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
data/lib/cli/version.rb
ADDED
metadata
ADDED
@@ -0,0 +1,59 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: cl
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Sven Fuchs
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2017-04-09 00:00:00.000000000 Z
|
12
|
+
dependencies: []
|
13
|
+
description: OptionParser based CLI support.
|
14
|
+
email: me@svenfuchs.com
|
15
|
+
executables: []
|
16
|
+
extensions: []
|
17
|
+
extra_rdoc_files: []
|
18
|
+
files:
|
19
|
+
- Gemfile
|
20
|
+
- Gemfile.lock
|
21
|
+
- MIT_LICENSE.md
|
22
|
+
- README.md
|
23
|
+
- lib/cli.rb
|
24
|
+
- lib/cli/cmd.rb
|
25
|
+
- lib/cli/cmds.rb
|
26
|
+
- lib/cli/format/cmd.rb
|
27
|
+
- lib/cli/format/list.rb
|
28
|
+
- lib/cli/format/table.rb
|
29
|
+
- lib/cli/format/usage.rb
|
30
|
+
- lib/cli/help.rb
|
31
|
+
- lib/cli/options.rb
|
32
|
+
- lib/cli/registry.rb
|
33
|
+
- lib/cli/runner.rb
|
34
|
+
- lib/cli/version.rb
|
35
|
+
homepage: https://github.com/svenfuchs/cl
|
36
|
+
licenses:
|
37
|
+
- MIT
|
38
|
+
metadata: {}
|
39
|
+
post_install_message:
|
40
|
+
rdoc_options: []
|
41
|
+
require_paths:
|
42
|
+
- lib
|
43
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - ">="
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '0'
|
48
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
49
|
+
requirements:
|
50
|
+
- - ">="
|
51
|
+
- !ruby/object:Gem::Version
|
52
|
+
version: '0'
|
53
|
+
requirements: []
|
54
|
+
rubyforge_project:
|
55
|
+
rubygems_version: 2.6.8
|
56
|
+
signing_key:
|
57
|
+
specification_version: 4
|
58
|
+
summary: OptionParser based CLI support
|
59
|
+
test_files: []
|