clin 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 98bdce921d4896c86ed482d8db5cf87a74b2795a
4
+ data.tar.gz: e025be0b4c3c5fd36f49437e21abfc1f00ef1a0c
5
+ SHA512:
6
+ metadata.gz: 8a70c2a7c6e53bf8eb781b37841dc24052e8396a2b6a2e8d73d6ea9dc90525fe1e03bf2437f43aefdeaf6aef648b210d7c79fec2fd8d7a31734c5ab21da7d9c1
7
+ data.tar.gz: ef60cf35207752817b52bae1514c55f5db9c12e5f87ae322a17469b9039b6a37470327c6bb4e4d43d37f024c5ae5acd283ec200090c6bad5f6705739086edd49
data/.codeclimate.yml ADDED
@@ -0,0 +1,5 @@
1
+ languages:
2
+ Ruby: true
3
+ exclude_paths:
4
+ - "spec/*"
5
+ - "examples/*"
data/.gitignore ADDED
@@ -0,0 +1,15 @@
1
+ /.bundle/
2
+ /.yardoc
3
+ /Gemfile.lock
4
+ /_yardoc/
5
+ /coverage/
6
+ /doc/
7
+ /pkg/
8
+ /spec/reports/
9
+ /tmp/
10
+ *.bundle
11
+ *.so
12
+ *.o
13
+ *.a
14
+ mkmf.log
15
+ .idea
data/.rubocop.yml ADDED
@@ -0,0 +1,19 @@
1
+ Metrics/LineLength:
2
+ Max: 100
3
+
4
+ Style/ClassAndModuleChildren:
5
+ Enabled: false
6
+
7
+ Style/SpaceInsideHashLiteralBraces:
8
+ EnforcedStyle: no_space
9
+
10
+ Metrics/MethodLength:
11
+ Description: Avoid methods longer than 25 lines of code.
12
+ Enabled: true
13
+ CountComments: false
14
+ Max: 25
15
+
16
+
17
+ AllCops:
18
+ Exclude:
19
+ - 'spec/**/*'
data/.travis.yml ADDED
@@ -0,0 +1,14 @@
1
+ language: ruby
2
+ rvm:
3
+ - '2.0'
4
+ - '2.1'
5
+ - '2.2'
6
+
7
+
8
+ gemfile:
9
+ - Gemfile
10
+
11
+ matrix:
12
+
13
+ notifications:
14
+ email: false
data/Gemfile ADDED
@@ -0,0 +1,10 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in clin.gemspec
4
+ gemspec
5
+
6
+ gem 'rubocop'
7
+ group :doc do
8
+ gem 'yard'
9
+ gem 'redcarpet'
10
+ end
data/LICENSE.txt ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2015 Timothee Guerin
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,98 @@
1
+ # Clin
2
+ [![Build Status](https://travis-ci.org/timcolonel/clin.svg?branch=master)](https://travis-ci.org/timcolonel/clin)
3
+ [![Coverage Status](https://coveralls.io/repos/timcolonel/clin/badge.svg?branch=master)](https://coveralls.io/r/timcolonel/clin?branch=master)
4
+ [![Code Climate](https://codeclimate.com/github/timcolonel/clin/badges/gpa.svg)](https://codeclimate.com/github/timcolonel/clin)
5
+
6
+ Clin is Command Line Interface library that provide an clean api for complex command configuration.
7
+ The way Clin is design allow a command defined by the user to be called via the command line as well as directly in the code without any additional configuration
8
+ ## Installation
9
+
10
+ Add this line to your application's Gemfile:
11
+
12
+ ```ruby
13
+ gem 'clin'
14
+ ```
15
+
16
+ And then execute:
17
+
18
+ $ bundle
19
+
20
+ Or install it yourself as:
21
+
22
+ $ gem install clin
23
+
24
+ Then add the following in you ruby script.
25
+ ```ruby
26
+ require 'clin'
27
+ ```
28
+ ## Usage
29
+
30
+ The [examples](examples/) folder contains various use case of Clin.
31
+
32
+ ### Define a command
33
+ To define a command you must create a new class that inherit `Clin::Command`:
34
+
35
+ ```ruby
36
+ class DisplayCommand < Clin::Command
37
+ def run
38
+
39
+ end
40
+ end
41
+ ```
42
+
43
+ #### Specify arguments
44
+ To specify what argument your command takes use the `.arguments` method.
45
+ Clin will then automatically extract the arguments when parsing and pass them when creating the object.
46
+ You can after access the arguments with @params
47
+ ```ruby
48
+ class DisplayCommand < Clin::Command
49
+ arguments 'display <message>'
50
+
51
+ def run
52
+ puts "Display message: #{params[:message}"
53
+ end
54
+ end
55
+ ```
56
+
57
+ Then calling `DisplayCommand.parse('display "Hello World!"').run` will print `Display message: Hello World!`
58
+
59
+ #### Specify options
60
+ You can also specify options using the `.option` method.
61
+ ```ruby
62
+ class DisplayCommand < Clin::Command
63
+ arguments 'display <message>'
64
+ option :times, 'Display the message n times'
65
+
66
+ def run
67
+ params[:times] ||= 1
68
+ params[:times].times.each do
69
+ puts "Display message: #{params[:message}"
70
+ end
71
+ end
72
+ end
73
+ ```
74
+
75
+ ### Dispatch to the right command
76
+ For complex command line interface you might need several different commands(e.g. git add, git commit,etc.)
77
+ Define each command as shown previously then use the CommandDispatcher to choose the right command.
78
+ By default the dispatcher is going to try all the loaded commands(All subclasses of Clin::Commands)
79
+ but it can be filter.
80
+ ```ruby
81
+ # Suppose Git::Add and Git::Commit are Clin::Command.
82
+ Clin::CommandDispatcher.parse('commit -m "initial commit") #=> Git::Commit<params: {message: "initial commit"}>
83
+ ```
84
+
85
+ To limit filter the usage:
86
+ ```ruby
87
+ # Suppose Git::Add, Git::Commit, Git::Push are Clin::Command.
88
+ dispatcher = Clin::CommandDispatcher.new(Git::Commit, Git::Push)
89
+ dispatcher.parse('commit add -A") #=> Will show the help as no command match.
90
+ dispatcher.parse('commit -m "initial commit") #=> Git::Commit<params: {message: "initial commit"}>
91
+ ```
92
+ ## Contributing
93
+
94
+ 1. Fork it ( https://github.com/timcolonel/clin/fork )
95
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
96
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
97
+ 4. Push to the branch (`git push origin my-new-feature`)
98
+ 5. Create a new Pull Request
data/Rakefile ADDED
@@ -0,0 +1,10 @@
1
+ require 'bundler/gem_tasks'
2
+
3
+ begin
4
+ require 'rspec/core/rake_task'
5
+
6
+ RSpec::Core::RakeTask.new(:spec)
7
+ task default: :spec
8
+ rescue LoadError
9
+ puts 'Spec cannot be loaded!'
10
+ end
data/clin.gemspec ADDED
@@ -0,0 +1,27 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'clin/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = 'clin'
8
+ spec.version = Clin::VERSION
9
+ spec.authors = ['Timothee Guerin']
10
+ spec.email = ['timothee.guerin@outlook.com']
11
+ spec.summary = 'Clin provide an advance way to define complex command line interface.'
12
+ spec.description = ''
13
+ spec.homepage = ''
14
+ spec.license = 'MIT'
15
+
16
+ spec.files = `git ls-files -z`.split("\x0")
17
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
18
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
19
+ spec.require_paths = ['lib']
20
+
21
+ spec.add_dependency 'activesupport', '>=4.0'
22
+ spec.add_development_dependency 'bundler', '~> 1.7'
23
+ spec.add_development_dependency 'rake', '~> 10.0'
24
+ spec.add_development_dependency 'rspec'
25
+ spec.add_development_dependency 'coveralls'
26
+ spec.add_development_dependency 'faker'
27
+ end
@@ -0,0 +1,76 @@
1
+ $LOAD_PATH.push File.expand_path('../../lib', __FILE__)
2
+ require 'clin'
3
+
4
+ # Simple command Example
5
+ class DisplayCommand < Clin::Command
6
+ arguments 'display <message>'
7
+
8
+ general_option Clin::HelpOptions
9
+
10
+ self.description = 'Display the given message'
11
+
12
+ def run
13
+ puts "Display: '#{params[:message]}'"
14
+ end
15
+ end
16
+
17
+ # Simple command Example
18
+ class PrintCommand < Clin::Command
19
+ arguments 'print <message>'
20
+
21
+ general_option Clin::HelpOptions
22
+
23
+ self.description = 'Print the given message'
24
+
25
+ def run
26
+ puts "Print: '#{params[:message]}'"
27
+ end
28
+ end
29
+
30
+ Clin::CommandDispatcher.parse('display "My Message"').run
31
+ puts
32
+ puts '=' * 60
33
+ puts
34
+ Clin::CommandDispatcher.parse('print "My Message"').run
35
+ puts
36
+ puts '=' * 60
37
+ puts
38
+ begin
39
+ Clin::CommandDispatcher.parse('display -h').run
40
+ rescue Clin::CommandLineError => e
41
+ puts e
42
+ end
43
+ puts
44
+ puts '=' * 60
45
+ puts
46
+ begin
47
+ Clin::CommandDispatcher.parse('-h')
48
+ rescue Clin::CommandLineError => e
49
+ puts e
50
+ end
51
+
52
+ # Output:
53
+ #
54
+ # $ ruby dispatcher.rb
55
+ # Display: 'My Message'
56
+ #
57
+ # ============================================================
58
+ #
59
+ # Print: 'My Message'
60
+ #
61
+ # ============================================================
62
+ #
63
+ # Usage: command display <message> [Options]
64
+ #
65
+ # Options:
66
+ # -h, --help Show the help.
67
+ #
68
+ # Description:
69
+ # Display the given message
70
+ #
71
+ #
72
+ # ============================================================
73
+ #
74
+ # Usage:
75
+ # command display <message> [Options]
76
+ # command print <message> [Options]
@@ -0,0 +1,91 @@
1
+ $LOAD_PATH.push File.expand_path('../../lib', __FILE__)
2
+ require 'clin'
3
+
4
+ # Simple dispatch Example
5
+ class DispatchCommand < Clin::Command
6
+ arguments 'you <args>...'
7
+ dispatch :args, prefix: 'you'
8
+ general_option Clin::HelpOptions
9
+
10
+ self.description = 'YOU print the given message'
11
+
12
+ def run
13
+ puts 'Should not be called'
14
+ end
15
+ end
16
+
17
+ # Simple command Example
18
+ class DisplayCommand < DispatchCommand
19
+ arguments 'you display <message>'
20
+
21
+ general_option Clin::HelpOptions
22
+
23
+ self.description = 'Display the given message'
24
+
25
+ def run
26
+ puts "I Display: '#{params[:message]}'"
27
+ end
28
+ end
29
+
30
+ # Simple command Example
31
+ class PrintCommand < DispatchCommand
32
+ arguments 'you print <message>'
33
+
34
+ general_option Clin::HelpOptions
35
+
36
+ self.description = 'Print the given message'
37
+
38
+ def run
39
+ puts "I Print: '#{params[:message]}'"
40
+ end
41
+ end
42
+
43
+
44
+ Clin::CommandDispatcher.parse('you display "My Message"').run
45
+ puts
46
+ puts '=' * 60
47
+ puts
48
+ Clin::CommandDispatcher.parse('you print "My Message"').run
49
+ puts
50
+ puts '=' * 60
51
+ puts
52
+ begin
53
+ Clin::CommandDispatcher.parse('you -h').run
54
+ rescue Clin::CommandLineError => e
55
+ puts e
56
+ end
57
+ puts
58
+ puts '=' * 60
59
+ puts
60
+ begin
61
+ Clin::CommandDispatcher.parse('-h')
62
+ rescue Clin::CommandLineError => e
63
+ puts e
64
+ end
65
+
66
+ # Output:
67
+ #
68
+ # $ ruby dispatcher.rb
69
+ # I Display: 'My Message'
70
+ #
71
+ # ============================================================
72
+ #
73
+ # I Print: 'My Message'
74
+ #
75
+ # ============================================================
76
+ #
77
+ # Usage: command you <args>... [Options]
78
+ #
79
+ # Options:
80
+ # -h, --help Show the help.
81
+ #
82
+ # Description:
83
+ # YOU print the given message
84
+ #
85
+ #
86
+ # ============================================================
87
+ #
88
+ # Usage:
89
+ # command you <args>... [Options]
90
+ # command you display <message> [Options]
91
+ # command you print <message> [Options]
@@ -0,0 +1,24 @@
1
+ $LOAD_PATH.push File.expand_path('../../lib', __FILE__)
2
+ require 'clin'
3
+
4
+ # Simple command Example
5
+ class OptionalArgumentCommand < Clin::Command
6
+ arguments 'display [<message>]'
7
+
8
+ def run
9
+ puts params.fetch(:message, 'No message given')
10
+ end
11
+ end
12
+
13
+ OptionalArgumentCommand.parse('display "My Message"')
14
+ puts
15
+ puts '=' * 60
16
+ puts
17
+ OptionalArgumentCommand.parse('display')
18
+
19
+ # $ ruby optional_argument.rb
20
+ # My Message
21
+ #
22
+ # ============================================================
23
+ #
24
+ # No message given
@@ -0,0 +1,39 @@
1
+ $LOAD_PATH.push File.expand_path('../../lib', __FILE__)
2
+ require 'clin'
3
+ require 'clin'
4
+
5
+ # Simple command Example
6
+ class SimpleCommand < Clin::Command
7
+ arguments 'display <message>'
8
+
9
+ option :echo, 'Echo some text'
10
+ general_option Clin::HelpOptions
11
+
12
+ def run
13
+ puts @params[:message]
14
+ puts @params[:echo]
15
+ end
16
+ end
17
+
18
+ if __FILE__== $0
19
+ SimpleCommand.parse('display "My Message" --echo SOME').run
20
+ puts
21
+ puts '=' * 60
22
+ puts
23
+ begin
24
+ SimpleCommand.parse('').run
25
+ rescue Clin::HelpError => e
26
+ puts e
27
+ end
28
+ end
29
+ # $ ruby simple.rb
30
+ # My Message
31
+ # SOME
32
+ #
33
+ # ============================================================
34
+ #
35
+ # Usage: command display <message> [Options]
36
+ #
37
+ # Options:
38
+ # -e, --echo ECHO Echo some text
39
+ # -h, --help Show the help.
data/examples/test.rb ADDED
@@ -0,0 +1,2 @@
1
+ $LOAD_PATH.push File.expand_path('../../lib', __FILE__)
2
+ require 'clin'
@@ -0,0 +1,90 @@
1
+ require 'clin'
2
+
3
+ # Command line positional argument(not option)
4
+ class Clin::Argument
5
+ attr_accessor :original
6
+ attr_accessor :optional
7
+ attr_accessor :multiple
8
+ attr_accessor :variable
9
+ attr_accessor :name
10
+
11
+ def initialize(argument)
12
+ @original = argument
13
+ @optional = false
14
+ @multiple = false
15
+ @variable = false
16
+ argument = check_optional(argument)
17
+ argument = check_multiple(argument)
18
+ @name = check_variable(argument)
19
+ end
20
+
21
+ def check_optional(argument)
22
+ if check_between(argument, '[', ']')
23
+ @optional = true
24
+ return argument[1...-1]
25
+ end
26
+ argument
27
+ end
28
+
29
+ def check_multiple(argument)
30
+ if argument.end_with? '...'
31
+ @multiple = true
32
+ return argument[0...-3]
33
+ end
34
+ argument
35
+ end
36
+
37
+ def check_variable(argument)
38
+ if check_between(argument, '<', '>')
39
+ @variable = true
40
+ return argument[1...-1]
41
+ end
42
+ argument
43
+ end
44
+
45
+ # Given a list of arguments extract the list of arguments that are matched
46
+ def parse(argv)
47
+ return handle_empty if argv.empty?
48
+ if @multiple
49
+ ensure_name(argv) unless @variable
50
+ [argv, []]
51
+ else
52
+ ensure_name(argv[0]) unless @variable
53
+ [argv[0], argv[1..-1]]
54
+ end
55
+ end
56
+
57
+ private
58
+
59
+ def ensure_name(args)
60
+ [*args].each do |arg|
61
+ if arg != @name
62
+ fail Clin::FixedArgumentError, @name, arg
63
+ end
64
+ end
65
+ end
66
+
67
+ # Call when the argv is empty.
68
+ # Will return nil, [] if the argument is optional
69
+ # Will fail otherwise:
70
+ # * MissingArgumentError if the argument is a variable(e.g. <arg>)
71
+ # * FixedArgumentError if the argument is fixed(e.g. display)
72
+ def handle_empty
73
+ return nil, [] if optional
74
+ if @variable
75
+ fail Clin::MissingArgumentError, @name
76
+ else
77
+ fail Clin::FixedArgumentError, @name
78
+ end
79
+ end
80
+
81
+ def check_between(argument, start_char, end_char)
82
+ if argument[0] == start_char
83
+ if argument[-1] != end_char
84
+ fail Clin::Error, "Argument format error! Cannot start with #{start_char} and not end with #{end_char}"
85
+ end
86
+ return true
87
+ end
88
+ false
89
+ end
90
+ end