clin 0.2.0 → 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 96826af1a7b6e82847b69c692292d7c2a10c69ed
4
- data.tar.gz: 28fd292aafc8be55a10af75853283a4def9def65
3
+ metadata.gz: be4386269225e68a69c419a0a4a90668f5da8287
4
+ data.tar.gz: 0a33c686511f6a0498fe40276c936b6574fbe497
5
5
  SHA512:
6
- metadata.gz: 3690346888ff69f711f292bca3f1e15a4580599ea12f070264b2c6eb6cdedc3f5081ac8113c08d2f391e1a892c6e6e36832d9351367ce83a924ab9ec801392e3
7
- data.tar.gz: 05d2c816d4140359ce2a01fca4462417b6c55fca85580fb7ffe7b8692b60498fe33b2dad151b21c783b7673b1a47f8e31a19215e1c63982a072e73a28345f1fd
6
+ metadata.gz: 2878f163e2974a9a3c93e9f565e9b5fdaf5ec91bcced8856b95b7045f45eca8427da8a22631f1741da582982ab1c575e19c6115cee4dd8078a69a08f217cf41d
7
+ data.tar.gz: eba57a52877c4ea5fca71571ab1a534459f173d9715028774b76a6be8fb9e7721b077fdc8371839ba770a43dfde17bd34fd7bf2c71e2001e88c6898be7458fab
data/.travis.yml CHANGED
@@ -1,6 +1,5 @@
1
1
  language: ruby
2
2
  rvm:
3
- - '2.0'
4
3
  - '2.1'
5
4
  - '2.2'
6
5
 
data/CHANGELOG.md CHANGED
@@ -1,7 +1,14 @@
1
+ ## 0.3.0
2
+ Features:
3
+ - Added a shell class for any user interaction.
4
+ - Added `priority` to test commands in specific order and not the order they where loaded.(#4)
5
+ - Added `auto_option` to define specific options cleaner.(#5)
6
+
1
7
  ## 0.2.0
2
8
  Features:
3
9
  - Allow unknown options to be ignored and not raise Error(#1)
4
10
  - Added list options. For options that can be multiple times in the same command(#2)
5
11
  - Added default value for options.(#3)
12
+
6
13
  ## 0.1.0
7
14
  Inital release.
data/README.md CHANGED
@@ -3,6 +3,7 @@
3
3
  [![Coverage Status](https://coveralls.io/repos/timcolonel/clin/badge.svg?branch=master)](https://coveralls.io/r/timcolonel/clin?branch=master)
4
4
  [![Code Climate](https://codeclimate.com/github/timcolonel/clin/badges/gpa.svg)](https://codeclimate.com/github/timcolonel/clin)
5
5
  [![Inline docs](http://inch-ci.org/github/timcolonel/clin.svg?branch=master)](http://inch-ci.org/github/timcolonel/clin)
6
+
6
7
  Clin is Command Line Interface library that provide an clean api for complex command configuration.
7
8
  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
9
  ## Installation
data/clin.gemspec CHANGED
@@ -21,7 +21,7 @@ Gem::Specification.new do |spec|
21
21
  spec.add_dependency 'activesupport', '>=4.0'
22
22
  spec.add_development_dependency 'bundler', '~> 1.7'
23
23
  spec.add_development_dependency 'rake', '~> 10.0'
24
- spec.add_development_dependency 'rspec'
24
+ spec.add_development_dependency 'rspec', '>= 3.0'
25
25
  spec.add_development_dependency 'coveralls'
26
26
  spec.add_development_dependency 'faker'
27
27
  end
@@ -0,0 +1,17 @@
1
+ $LOAD_PATH.push File.expand_path('../../lib', __FILE__)
2
+ require 'clin'
3
+ require 'clin'
4
+
5
+ # Simple command Example
6
+ class AutoOptionCommand < Clin::Command
7
+ auto_option :echo, '-e --eko=message Echo the message'
8
+ general_option Clin::HelpOptions
9
+
10
+ def run
11
+ puts @params[:echo]
12
+ end
13
+ end
14
+
15
+ # Run example:
16
+ # AutoOptionCommand.parse('-e "Some message 1"').run
17
+ # AutoOptionCommand.parse('--eko="Some message 2"').run
@@ -5,7 +5,7 @@ require 'clin'
5
5
  class DisplayCommand < Clin::Command
6
6
  arguments 'display <message>'
7
7
 
8
- self.description = 'Display the given message'
8
+ description 'Display the given message'
9
9
 
10
10
  def run
11
11
  puts "Display: '#{params[:message]}'"
@@ -16,33 +16,27 @@ end
16
16
  class PrintCommand < Clin::Command
17
17
  arguments 'print <message>'
18
18
 
19
- self.description = 'Print the given message'
19
+ description 'Print the given message'
20
20
 
21
21
  def run
22
22
  puts "Print: '#{params[:message]}'"
23
23
  end
24
24
  end
25
25
 
26
- if __FILE__ == $PROGRAM_NAME
27
- Clin::CommandDispatcher.parse('display "My Message"').run
28
- puts
29
- puts '=' * 60
30
- puts
31
- Clin::CommandDispatcher.parse('print "My Message"').run
32
- puts
33
- puts '=' * 60
34
- puts
35
- begin
36
- Clin::CommandDispatcher.parse('display -h').run
37
- rescue Clin::CommandLineError => e
38
- puts e
39
- end
40
- puts
41
- puts '=' * 60
42
- puts
43
- begin
44
- Clin::CommandDispatcher.parse('-h')
45
- rescue Clin::CommandLineError => e
46
- puts e
26
+ # Simple command Example
27
+ class PrintAltCommand < Clin::Command
28
+ arguments 'print <message>'
29
+
30
+ description 'Print the given message alternative'
31
+ prioritize
32
+
33
+ def run
34
+ puts "Print alt: '#{params[:message]}'"
47
35
  end
48
36
  end
37
+
38
+ # Example of run:
39
+ # Clin::CommandDispatcher.parse('display "My Message"').run
40
+ # Clin::CommandDispatcher.parse('print "My Message"').run
41
+ # Clin::CommandDispatcher.parse('display -h').run
42
+ # Clin::CommandDispatcher.parse('-h')
@@ -17,11 +17,6 @@ class ListCommand < Clin::Command
17
17
  end
18
18
  end
19
19
  end
20
-
21
- if __FILE__ == $PROGRAM_NAME
22
- ListCommand.parse('--echo "Message 1" --echo "Message 2"').run
23
- puts
24
- puts '=' * 60
25
- puts
26
- ListCommand.parse('--echo "Message 3" --echo "Message 4" -ll').run
27
- end
20
+ # Use examples:
21
+ # ListCommand.parse('--echo "Message 1" --echo "Message 2"').run
22
+ # ListCommand.parse('--echo "Message 3" --echo "Message 4" -ll').run
@@ -9,7 +9,7 @@ class DispatchCommand < Clin::Command
9
9
 
10
10
  flag_option :verbose, 'Verbose the output'
11
11
 
12
- self.description = 'YOU print the given message'
12
+ description 'YOU print the given message'
13
13
 
14
14
  def run
15
15
  puts 'Should not be called'
@@ -22,7 +22,7 @@ class DisplayCommand < DispatchCommand
22
22
  option :echo, 'Display more text'
23
23
  option :times, 'Display the text multiple times', type: Integer
24
24
 
25
- self.description = 'Display the given message'
25
+ description 'Display the given message'
26
26
 
27
27
  def run
28
28
  puts "I Display: '#{params[:message]}'"
@@ -33,60 +33,15 @@ end
33
33
  class PrintCommand < DispatchCommand
34
34
  arguments 'you print <message>'
35
35
 
36
- self.description = 'Print the given message'
36
+ description 'Print the given message'
37
37
 
38
38
  def run
39
39
  puts "I Print: '#{params[:message]}'"
40
40
  end
41
41
  end
42
42
 
43
- if __FILE__ == $PROGRAM_NAME
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
- end
66
-
67
- # Output:
68
- #
69
- # $ ruby dispatcher.rb
70
- # I Display: 'My Message'
71
- #
72
- # ============================================================
73
- #
74
- # I Print: 'My Message'
75
- #
76
- # ============================================================
77
- #
78
- # Usage: command you <args>... [Options]
79
- #
80
- # Options:
81
- # -h, --help Show the help.
82
- #
83
- # Description:
84
- # YOU print the given message
85
- #
86
- #
87
- # ============================================================
88
- #
89
- # Usage:
90
- # command you <args>... [Options]
91
- # command you display <message> [Options]
92
- # command you print <message> [Options]
43
+ # Example of run:
44
+ # Clin::CommandDispatcher.parse('you display "My Message"').run
45
+ # Clin::CommandDispatcher.parse('you print "My Message"').run
46
+ # Clin::CommandDispatcher.parse('you -h').run
47
+ # Clin::CommandDispatcher.parse('-h')
data/examples/simple.rb CHANGED
@@ -15,25 +15,6 @@ class SimpleCommand < Clin::Command
15
15
  end
16
16
  end
17
17
 
18
- if __FILE__ == $PROGRAM_NAME
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.
18
+ # Run example:
19
+ # SimpleCommand.parse('display "My Message" --echo SOME').run
20
+ # SimpleCommand.parse('').run
data/examples/test.rb CHANGED
@@ -1,9 +1,9 @@
1
- $LOAD_PATH.push File.expand_path('../../lib', __FILE__)
2
- require 'clin'
3
-
4
- a = [1, 2, 3]
5
-
6
- b, c = a
7
-
8
- puts b
9
- puts c
1
+ $LOAD_PATH.push File.expand_path('../../lib', __FILE__)
2
+ require 'clin'
3
+
4
+
5
+ shell = Clin::Shell.new
6
+
7
+ choice = shell.choose('What?', %w(france usa italy germany))
8
+
9
+ puts 'YOu ' + choice
data/lib/clin/argument.rb CHANGED
@@ -20,7 +20,7 @@ class Clin::Argument
20
20
 
21
21
  # Check if the argument is optional(i.e [arg])
22
22
  def check_optional(argument)
23
- if beck_between(argument, '[', ']')
23
+ if check_between(argument, '[', ']')
24
24
  @optional = true
25
25
  return argument[1...-1]
26
26
  end
@@ -38,7 +38,7 @@ class Clin::Argument
38
38
 
39
39
  # Check if the argument is variable(i.e <arg>)
40
40
  def check_variable(argument)
41
- if beck_between(argument, '<', '>')
41
+ if check_between(argument, '<', '>')
42
42
  @variable = true
43
43
  return argument[1...-1]
44
44
  end
@@ -94,7 +94,7 @@ class Clin::Argument
94
94
  # beck_between('[<arg>]', '<'. '>') # => false
95
95
  # beck_between('[<arg>', '<'. '>') # => raise Clin::Error
96
96
  # ```
97
- def beck_between(argument, start_char, end_char)
97
+ def check_between(argument, start_char, end_char)
98
98
  if argument[0] == start_char
99
99
  if argument[-1] != end_char
100
100
  fail Clin::Error, "Argument format error! Cannot start
data/lib/clin/command.rb CHANGED
@@ -1,83 +1,15 @@
1
1
  require 'clin'
2
- require 'clin/command_options_mixin'
3
2
  require 'clin/argument'
4
3
  require 'shellwords'
5
4
  require 'clin/common/help_options'
6
5
 
7
6
  # Clin Command
8
- class Clin::Command < Clin::CommandOptionsMixin
9
- class_attribute :args
10
- class_attribute :description
7
+ class Clin::Command
8
+ include Clin::CommandMixin::Core
9
+ include Clin::CommandMixin::Dispatcher
10
+ include Clin::CommandMixin::Options
11
11
 
12
- # Redispatch will be reset to nil when inheriting a dispatcher command
13
- class_attribute :_redispatch_args
14
- class_attribute :_abstract
15
- class_attribute :_exe_name
16
- class_attribute :_skip_options
17
-
18
- self.args = []
19
- self.description = ''
20
- self._abstract = false
21
- self._skip_options = false
22
-
23
- # Trigger when a class inherit this class
24
- # Rest class_attributes that should not be shared with subclass
25
- # @param subclass [Clin::Command]
26
- def self.inherited(subclass)
27
- subclass._redispatch_args = nil
28
- subclass._abstract = false
29
- subclass._skip_options = false
30
- super
31
- end
32
-
33
- # Mark the class as abstract
34
- def self.abstract(value)
35
- self._abstract = value
36
- end
37
-
38
- # Set or get the exe name.
39
- # Executable name that will be display in the usage.
40
- # If exe_name is not set in a class or it's parent it will use the global setting Clin.exe_name
41
- # @param value [String] name of the exe.
42
- # ```
43
- # class Git < Clin::Command
44
- # exe_name 'git'
45
- # arguments '<command> <args>...'
46
- # end
47
- # Git.usage # => git <command> <args>...
48
- # ```
49
- def self.exe_name(value = nil)
50
- self._exe_name = value unless value.nil?
51
- self._exe_name ||= Clin.exe_name
52
- end
53
-
54
- def self.skip_options(value)
55
- self._skip_options = value
56
- end
57
-
58
- def self.skip_options?
59
- _skip_options
60
- end
61
-
62
- def self.redispatch?
63
- !_redispatch_args.nil?
64
- end
65
-
66
- def self.arguments(args)
67
- self.args = []
68
- [*args].map(&:split).flatten.each do |arg|
69
- self.args += [Clin::Argument.new(arg)]
70
- end
71
- end
72
-
73
- def self.usage
74
- a = [exe_name, args.map(&:original).join(' '), '[Options]']
75
- a.reject(&:blank?).join(' ')
76
- end
77
-
78
- def self.banner
79
- "Usage: #{usage}"
80
- end
12
+ general_option 'Clin::HelpOptions'
81
13
 
82
14
  # Parse the command and initialize the command object with the parsed options
83
15
  # @param argv [Array|String] command line to parse.
@@ -86,63 +18,16 @@ class Clin::Command < Clin::CommandOptionsMixin
86
18
  parser.parse
87
19
  end
88
20
 
89
- # Build the Option Parser object
90
- # Used to parse the option
91
- # Useful for regenerating the help as well.
92
- def self.option_parser(out = {})
93
- OptionParser.new do |opts|
94
- opts.banner = banner
95
- opts.separator ''
96
- opts.separator 'Options:'
97
- register_options(opts, out)
98
- dispatch_doc(opts)
99
- unless description.blank?
100
- opts.separator "\nDescription:"
101
- opts.separator description
102
- end
103
- opts.separator ''
104
- end
105
- end
106
-
107
- # Redispatch the command to a sub command with the given arguments
108
- # @param args [Array<String>|String] New argument to parse
109
- # @param prefix [String] Prefix to add to the beginning of the command
110
- # @param commands [Array<Clin::Command.class>] Commands that will be tried against
111
- # If no commands are given it will look for Clin::Command in the class namespace
112
- # e.g. If those 2 classes are defined.
113
- # `MyDispatcher < Clin::Command` and `MyDispatcher::ChildCommand < Clin::Command`
114
- # Will test against ChildCommand
115
- def self.dispatch(args, prefix: nil, commands: nil)
116
- self._redispatch_args = [[*args], prefix, commands]
117
- end
118
-
119
- def self.dispatch_doc(opts)
120
- return if _redispatch_args.nil?
121
- opts.separator 'Examples: '
122
- commands = (_redispatch_args[2] || default_commands)
123
- commands.each do |cmd_cls|
124
- opts.separator "\t#{cmd_cls.usage}"
125
- end
126
- end
127
-
128
- def self.default_commands
129
- # self.constants.map { |c| self.const_get(c) }
130
- # .select { |c| c.is_a?(Class) && (c < Clin::Command) }
131
- subcommands
132
- end
133
-
134
- # List the subcommands
135
- # The subcommands are all the Classes inheriting this one that are not set to abstract
136
- def self.subcommands
137
- subclasses.reject(&:_abstract)
138
- end
139
-
140
- general_option 'Clin::HelpOptions'
141
-
21
+ # Contains the parameters
142
22
  attr_accessor :params
143
23
 
24
+ # Contains a shell object for user interaction in the command
25
+ # @see Clin::Shell
26
+ attr_accessor :shell
27
+
144
28
  def initialize(params = {})
145
29
  @params = params
30
+ @shell = Clin::Shell.new
146
31
  self.class.execute_general_options(params)
147
32
  end
148
33
  end
@@ -0,0 +1,152 @@
1
+ require 'clin'
2
+
3
+ # Contains the core class methods for the command mixin
4
+ module Clin::CommandMixin::Core
5
+ extend ActiveSupport::Concern
6
+ included do
7
+ @_arguments = []
8
+ @_default_priority = 1000
9
+ @_priority = 0
10
+ end
11
+
12
+ module ClassMethods # :nodoc:
13
+ attr_accessor :_arguments
14
+ attr_accessor :_description
15
+ attr_accessor :_abstract
16
+ attr_accessor :_exe_name
17
+ attr_accessor :_skip_options
18
+ attr_accessor :_default_priority
19
+ attr_accessor :_priority
20
+
21
+ # Trigger when a class inherit this class
22
+ # Rest class_attributes that should not be shared with subclass
23
+ # @param subclass [Clin::Command]
24
+ def inherited(subclass)
25
+ subclass._arguments = []
26
+ subclass._description = ''
27
+ subclass._abstract = false
28
+ subclass._skip_options = false
29
+ subclass._exe_name = @_exe_name
30
+ subclass._default_priority = @_default_priority.to_f / 2
31
+ subclass._priority = 0
32
+ super
33
+ end
34
+
35
+ # Mark the class as abstract
36
+ def abstract(value)
37
+ @_abstract = value
38
+ end
39
+
40
+ # Return if the current command class is abstract
41
+ # @return [Boolean]
42
+ def abstract?
43
+ @_abstract
44
+ end
45
+
46
+ # Set or get the exe name.
47
+ # Executable name that will be display in the usage.
48
+ # If exe_name is not set in a class or it's parent it will use the global setting Clin.exe_name
49
+ # @param value [String] name of the exe.
50
+ # ```
51
+ # class Git < Clin::Command
52
+ # exe_name 'git'
53
+ # arguments '<command> <args>...'
54
+ # end
55
+ # Git.usage # => git <command> <args>...
56
+ # ```
57
+ def exe_name(value = nil)
58
+ @_exe_name = value unless value.nil?
59
+ @_exe_name ||= Clin.exe_name
60
+ end
61
+
62
+ # Allow the current option to skip unknown options.
63
+ # @param value [Boolean] skip or not
64
+ def skip_options(value)
65
+ @_skip_options = value
66
+ end
67
+
68
+ # Is the current command skipping options
69
+ def skip_options?
70
+ @_skip_options
71
+ end
72
+
73
+ # Set or get the arguments for the command
74
+ # @param args [Array<String>] List of arguments to set. If nil it just return the current args.
75
+ def arguments(args = nil)
76
+ return @_arguments if args.nil?
77
+ @_arguments = []
78
+ [*args].map(&:split).flatten.each do |arg|
79
+ @_arguments << Clin::Argument.new(arg)
80
+ end
81
+ end
82
+
83
+ alias_method :args, :arguments
84
+
85
+ # Set or get the description
86
+ # @param desc [String] Description to set. If nil it just return the current value.
87
+ def description(desc = nil)
88
+ @_description = desc unless desc.nil?
89
+ @_description
90
+ end
91
+
92
+ def usage
93
+ a = [exe_name, @_arguments.map(&:original).join(' '), '[Options]']
94
+ a.reject(&:blank?).join(' ')
95
+ end
96
+
97
+ def banner
98
+ "Usage: #{usage}"
99
+ end
100
+
101
+ # Priorities this command.
102
+ # This does not set the priority. It add +value+ to the default priority
103
+ # The default priority is computed using half of the parent default priority.
104
+ # e.g.
105
+ # ```
106
+ # Parent = Class.new(Clin::Command)
107
+ # Child1 = Class.new(Parent)
108
+ # Child2 = Class.new(Parent)
109
+ # Parent.priority # => 500
110
+ # Child1.priority # => 250
111
+ # Child2.priority # => 250
112
+ # Child2.prioritize
113
+ # Child2.priority # => 251
114
+ # ```
115
+ # When dispatching commands they are sorted by priority
116
+ def prioritize(value = 1)
117
+ @_priority = value
118
+ end
119
+
120
+ def priority
121
+ @_default_priority + @_priority
122
+ end
123
+
124
+ # Build the Option Parser object
125
+ # Used to parse the option
126
+ # Useful for regenerating the help as well.
127
+ def option_parser(out = {})
128
+ OptionParser.new do |opts|
129
+ opts.banner = banner
130
+ opts.separator ''
131
+ opts.separator 'Options:'
132
+ register_options(opts, out)
133
+ dispatch_doc(opts)
134
+ unless @description.blank?
135
+ opts.separator "\nDescription:"
136
+ opts.separator @description
137
+ end
138
+ opts.separator ''
139
+ end
140
+ end
141
+
142
+ def default_commands
143
+ subcommands.sort_by(&:priority).reverse
144
+ end
145
+
146
+ # List the subcommands
147
+ # The subcommands are all the Classes inheriting this one that are not set to abstract
148
+ def subcommands
149
+ subclasses.reject(&:abstract?)
150
+ end
151
+ end
152
+ end
@@ -0,0 +1,34 @@
1
+ require 'clin'
2
+
3
+ # Dispatcher mixin contains the class methods for command that need to redispatch to subcommands
4
+ module Clin::CommandMixin::Dispatcher
5
+ extend ActiveSupport::Concern
6
+ module ClassMethods # :nodoc:
7
+ attr_accessor :_redispatch_args
8
+
9
+ # Redispatch the command to a sub command with the given arguments
10
+ # @param args [Array<String>|String] New argument to parse
11
+ # @param prefix [String] Prefix to add to the beginning of the command
12
+ # @param commands [Array<Clin::Command.class>] Commands that will be tried against
13
+ # If no commands are given it will look for Clin::Command in the class namespace
14
+ # e.g. If those 2 classes are defined.
15
+ # `MyDispatcher < Clin::Command` and `MyDispatcher::ChildCommand < Clin::Command`
16
+ # Will test against ChildCommand
17
+ def dispatch(args, prefix: nil, commands: nil)
18
+ @_redispatch_args = [[*args], prefix, commands]
19
+ end
20
+
21
+ def redispatch?
22
+ !@_redispatch_args.nil?
23
+ end
24
+
25
+ def dispatch_doc(opts)
26
+ return if _redispatch_args.nil?
27
+ opts.separator 'Examples: '
28
+ commands = (_redispatch_args[2] || default_commands)
29
+ commands.each do |cmd_cls|
30
+ opts.separator "\t#{cmd_cls.usage}"
31
+ end
32
+ end
33
+ end
34
+ end