cl 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -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
@@ -0,0 +1,3 @@
1
+ group :test do
2
+ gem 'rspec'
3
+ end
@@ -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
@@ -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.
@@ -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
+ ```
@@ -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
@@ -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
@@ -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
@@ -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
@@ -0,0 +1,11 @@
1
+ module Cli
2
+ class Options < OptionParser
3
+ attr_reader :opts
4
+
5
+ def initialize(opts, args)
6
+ @opts = {}
7
+ super { opts.each { |args, block| on(*args) { |*args| instance_exec(*args, &block) } } }
8
+ parse!(args)
9
+ end
10
+ end
11
+ end
@@ -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
@@ -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
@@ -0,0 +1,3 @@
1
+ module Cli
2
+ VERSION = '0.0.1'
3
+ end
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: []