brigadier 0.1.1

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: 431da2466bfb9ba4a5fe0a707750c53ac4ea72b1
4
+ data.tar.gz: a17acb0890b983e00f53d844c5fb772ac04b6913
5
+ SHA512:
6
+ metadata.gz: b3db515f7c16e7a5aed234fe5a3347ec843df2415bdd3cb0c1457860de2930624d6d478fd7dc24297607943bab1643b17c7e746012474095b07d6dfd9b460e01
7
+ data.tar.gz: 1409c9d0a8dee921bff68854025fba1e27f210fa46ff5a00c336b968ad81a038290d7155af5eb49b1338a9db4853020c4f80eaf515fefa58aa742794c28388b8
data/.gitignore ADDED
@@ -0,0 +1,9 @@
1
+ /.bundle/
2
+ /.yardoc
3
+ /Gemfile.lock
4
+ /_yardoc/
5
+ /coverage/
6
+ /doc/
7
+ /pkg/
8
+ /spec/reports/
9
+ /tmp/
data/.rspec ADDED
@@ -0,0 +1,2 @@
1
+ --format documentation
2
+ --color
data/.rubocop.yml ADDED
@@ -0,0 +1,20 @@
1
+ Style/SpaceInsideBrackets:
2
+ Enabled: false
3
+
4
+ Style/EmptyLinesAroundClassBody:
5
+ Enabled: false
6
+
7
+ Style/Documentation:
8
+ Enabled: false
9
+
10
+ Style/IndentationConsistency:
11
+ Enabled: false
12
+
13
+ Style/FormatString:
14
+ Enabled: false
15
+
16
+ Metrics/LineLength:
17
+ Enabled: false
18
+
19
+ Style/GlobalVars:
20
+ Enabled: false
data/.travis.yml ADDED
@@ -0,0 +1,4 @@
1
+ language: ruby
2
+ rvm:
3
+ - 2.2.3
4
+ before_install: gem install bundler -v 1.11.0
@@ -0,0 +1,49 @@
1
+ # Contributor Code of Conduct
2
+
3
+ As contributors and maintainers of this project, and in the interest of
4
+ fostering an open and welcoming community, we pledge to respect all people who
5
+ contribute through reporting issues, posting feature requests, updating
6
+ documentation, submitting pull requests or patches, and other activities.
7
+
8
+ We are committed to making participation in this project a harassment-free
9
+ experience for everyone, regardless of level of experience, gender, gender
10
+ identity and expression, sexual orientation, disability, personal appearance,
11
+ body size, race, ethnicity, age, religion, or nationality.
12
+
13
+ Examples of unacceptable behavior by participants include:
14
+
15
+ * The use of sexualized language or imagery
16
+ * Personal attacks
17
+ * Trolling or insulting/derogatory comments
18
+ * Public or private harassment
19
+ * Publishing other's private information, such as physical or electronic
20
+ addresses, without explicit permission
21
+ * Other unethical or unprofessional conduct
22
+
23
+ Project maintainers have the right and responsibility to remove, edit, or
24
+ reject comments, commits, code, wiki edits, issues, and other contributions
25
+ that are not aligned to this Code of Conduct, or to ban temporarily or
26
+ permanently any contributor for other behaviors that they deem inappropriate,
27
+ threatening, offensive, or harmful.
28
+
29
+ By adopting this Code of Conduct, project maintainers commit themselves to
30
+ fairly and consistently applying these principles to every aspect of managing
31
+ this project. Project maintainers who do not follow or enforce the Code of
32
+ Conduct may be permanently removed from the project team.
33
+
34
+ This code of conduct applies both within project spaces and in public spaces
35
+ when an individual is representing the project or its community.
36
+
37
+ Instances of abusive, harassing, or otherwise unacceptable behavior may be
38
+ reported by contacting a project maintainer at ash@the-rebellion.net. All
39
+ complaints will be reviewed and investigated and will result in a response that
40
+ is deemed necessary and appropriate to the circumstances. Maintainers are
41
+ obligated to maintain confidentiality with regard to the reporter of an
42
+ incident.
43
+
44
+ This Code of Conduct is adapted from the [Contributor Covenant][homepage],
45
+ version 1.3.0, available at
46
+ [http://contributor-covenant.org/version/1/3/0/][version]
47
+
48
+ [homepage]: http://contributor-covenant.org
49
+ [version]: http://contributor-covenant.org/version/1/3/0/
data/Gemfile ADDED
@@ -0,0 +1,5 @@
1
+ source 'https://rubygems.org'
2
+
3
+ gemspec
4
+
5
+ gem 'pry-byebug'
data/LICENSE.txt ADDED
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2015 Ash McKenzie
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,83 @@
1
+ # Brigadier
2
+
3
+ Brigadier - Take control of your command line
4
+
5
+ ## Installation
6
+
7
+ Add this line to your application's Gemfile:
8
+
9
+ ```ruby
10
+ gem 'brigadier'
11
+ ```
12
+
13
+ And then execute:
14
+
15
+ $ bundle
16
+
17
+ Or install it yourself as:
18
+
19
+ $ gem install brigadier
20
+
21
+ ## Usage
22
+
23
+ Add the following to `basic.rb`:
24
+
25
+ ```ruby
26
+ #!/usr/bin/env ruby
27
+
28
+ require 'brigadier'
29
+
30
+ class BasicCommand
31
+ extend Brigadier
32
+
33
+ toggle 'debug', 'Debugging toggle'
34
+ toggle 'verbose', 'Verbose mode', default: true
35
+
36
+ execute do
37
+ puts "Inside \#execute - debug?: #{debug?}, verbose?: #{verbose?}"
38
+ end
39
+ end
40
+
41
+ Brigadier::Runner.new(ARGV).run(BasicCommand)
42
+ ```
43
+
44
+ Get some help:
45
+
46
+ ```shell
47
+ $ ruby basic.rb --help
48
+
49
+ Toggle(s)
50
+ --debug Debugging toggle (default: false)
51
+ --verbose Verbose mode (default: true)
52
+
53
+ $ ruby basic.rb --debug --help
54
+
55
+ Toggle(s)
56
+ --debug Debugging toggle (default: false, current: true)
57
+ --verbose Verbose mode (default: true)
58
+ ```
59
+
60
+ Run it:
61
+
62
+ ```shell
63
+ $ ruby basic.rb
64
+ Inside #execute - debug?: false, verbose?: true
65
+
66
+ $ ruby basic.rb --debug --not-verbose
67
+ Inside #execute - debug?: true, verbose?: false
68
+ ```
69
+
70
+ Check out the [examples](./examples) directory for more examples.
71
+
72
+ ## Contributing
73
+
74
+ 1. Fork it ( https://github.com/ashmckenzie/brigadier/fork )
75
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
76
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
77
+ 4. Run `bundle exec rake test`
78
+ 5. Push to the branch (`git push origin my-new-feature`)
79
+ 6. Create a new Pull Request
80
+
81
+ ## License
82
+
83
+ The gem is available as open source under the terms of the [MIT License](http://opensource.org/licenses/MIT).
data/Rakefile ADDED
@@ -0,0 +1,8 @@
1
+ require 'bundler/gem_tasks'
2
+ require 'rspec/core/rake_task'
3
+ require 'rubocop/rake_task'
4
+
5
+ RSpec::Core::RakeTask.new(:spec)
6
+ RuboCop::RakeTask.new
7
+
8
+ task default: [ :rubocop, :spec ]
data/brigadier.gemspec ADDED
@@ -0,0 +1,25 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'brigadier/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = 'brigadier'
8
+ spec.version = Brigadier::VERSION
9
+ spec.authors = ['Ash McKenzie']
10
+ spec.email = ['ash@the-rebellion.net']
11
+
12
+ spec.summary = 'Brigadier - Take control of your command line'
13
+ spec.description = 'Brigadier is a DSL that provides the ability to create complex command line tools with support for - sub commands, arguments, options and toggles'
14
+ spec.homepage = 'https://github.com/ashmckenzie'
15
+ spec.license = 'MIT'
16
+
17
+ spec.files = `git ls-files`.split("\n").reject { |f| f.match(%r{^(test|spec|features)/}) }
18
+ spec.require_paths = ['lib']
19
+
20
+ spec.add_development_dependency 'bundler', '~> 1.11'
21
+ spec.add_development_dependency 'rake', '~> 10.0'
22
+ spec.add_development_dependency 'rspec', '~> 3.0'
23
+ spec.add_development_dependency 'rubocop', '~> 0.37'
24
+ spec.add_development_dependency 'simplecov', '~> 0.11'
25
+ end
@@ -0,0 +1,109 @@
1
+ require 'brigadier'
2
+
3
+ # You can run like so:
4
+ #
5
+ # ruby advanced.rb --help
6
+ # ruby advanced.rb
7
+ # ruby advanced.rb --debug
8
+ # ruby advanced.rb admin --help
9
+ # ruby advanced.rb admin
10
+ # ruby advanced.rb admin 'Poopy McPoopy'
11
+ # ruby advanced.rb admin 'John Smith'
12
+ # ruby advanced.rb admin --age 27 'John Smith'
13
+ # ruby advanced.rb admin --age 200 'John Smith' 'john@smith.com'
14
+ # ruby advanced.rb admin --important 'John Smith' 'john@smith.com'
15
+ # ruby advanced.rb admin --not-sensitive 'John Smith' 'john@smith.com'
16
+
17
+ module CustomValidations
18
+ class AntiPooper
19
+ include Brigadier::Validators::Base
20
+
21
+ def failure_message
22
+ "Please don't mention poop."
23
+ end
24
+
25
+ def valid?
26
+ !value.match(/poop/i)
27
+ end
28
+ end
29
+
30
+ class SensibleAge
31
+ include Brigadier::Validators::Base
32
+
33
+ VALID_AGE_START = 20
34
+ VALID_AGE_END = 100
35
+
36
+ def failure_message
37
+ '%s is not a sensible age (needs to be between %s and %s)' % [ value, VALID_AGE_START, VALID_AGE_END ]
38
+ end
39
+
40
+ def value
41
+ obj.value.to_i
42
+ end
43
+
44
+ def valid?
45
+ value >= VALID_AGE_START && value <= VALID_AGE_END
46
+ end
47
+ end
48
+ end
49
+
50
+ module Commands
51
+ class Default
52
+ extend Brigadier
53
+
54
+ toggle 'debug', 'Debugging toggle'
55
+ toggle 'verbose', 'Verbose mode', default: true
56
+ argument 'name', 'Name of person'
57
+
58
+ execute do
59
+ puts "Inside \#execute: name: #{name}, debug?: #{debug?}, verbose?: #{verbose?}"
60
+ end
61
+ end
62
+ end
63
+
64
+ module SubCommands
65
+ class GuestAndAdmin
66
+ extend Brigadier
67
+
68
+ DAYS_IN_A_YEAR = 365
69
+
70
+ toggle 'debug', 'Debugging'
71
+
72
+ sub_command 'guest', 'Guest sub command' do
73
+ argument 'name', 'Name of guest', validators: [ CustomValidations::AntiPooper ]
74
+
75
+ execute do
76
+ puts "Inside guest sub command's \#execute: name: #{name} debug?: #{debug?}"
77
+ end
78
+ end
79
+
80
+ sub_command 'admin', 'Admin sub command' do
81
+ toggle 'important', 'Important'
82
+ toggle 'sensitive', 'Sensitive', default: true
83
+
84
+ argument 'name', 'Name of admin', validators: [ CustomValidations::AntiPooper ]
85
+ argument 'email', 'Email of admin', validators: [ Brigadier::Validators::Email ]
86
+
87
+ option 'age', 'Age', default: 25, validators: [ CustomValidations::SensibleAge ] { |age| age.to_i }
88
+
89
+ def age_in_days
90
+ age * DAYS_IN_A_YEAR
91
+ end
92
+
93
+ execute do
94
+ puts <<-EOS
95
+ Inside admin sub command's \#execute:
96
+ name: #{name}
97
+ email: #{email}
98
+ age: #{age}
99
+ age in days: #{age_in_days}
100
+ debug?: #{debug?}
101
+ important?: #{important?}
102
+ sensitive?: #{sensitive?}
103
+ EOS
104
+ end
105
+ end
106
+ end
107
+ end
108
+
109
+ Brigadier::Runner.new(ARGV).run(Commands::Default, SubCommands::GuestAndAdmin)
data/examples/basic.rb ADDED
@@ -0,0 +1,19 @@
1
+ require 'brigadier'
2
+
3
+ # You can run like so:
4
+ #
5
+ # ruby basic.rb --help
6
+ # ruby basic.rb
7
+
8
+ class BasicCommand
9
+ extend Brigadier
10
+
11
+ toggle 'debug', 'Debugging toggle'
12
+ toggle 'verbose', 'Verbose mode', default: true
13
+
14
+ execute do
15
+ puts "Inside \#execute - debug?: #{debug?}, verbose?: #{verbose?}"
16
+ end
17
+ end
18
+
19
+ Brigadier::Runner.new(ARGV).run(BasicCommand)
@@ -0,0 +1,28 @@
1
+ require 'brigadier'
2
+
3
+ # You can run like so:
4
+ #
5
+ # ruby intermediate.rb
6
+ # ruby intermediate.rb --help
7
+ # ruby intermediate.rb guest
8
+ # ruby intermediate.rb guest --help
9
+ # ruby intermediate.rb guest --debug 'John Smith'
10
+
11
+ module Commands
12
+ class Intermediate
13
+ extend Brigadier
14
+
15
+ toggle 'debug', 'Debugging toggle'
16
+ toggle 'verbose', 'Verbose mode', default: true
17
+
18
+ sub_command 'guest', 'Guest sub command' do
19
+ argument 'name', 'Name of guest', required: true
20
+
21
+ execute do
22
+ puts "Inside guest sub command's \#execute: name: #{name}, debug?: #{debug?}, verbose?: #{verbose?}"
23
+ end
24
+ end
25
+ end
26
+ end
27
+
28
+ Brigadier::Runner.new(ARGV).run(Commands::Intermediate)
@@ -0,0 +1,117 @@
1
+ module Brigadier
2
+ module Commands
3
+ module Base
4
+ include Helper
5
+
6
+ def process_args(args, obj)
7
+ args_to_keep = []
8
+ until args.empty?
9
+ arg = args.shift
10
+ if option_or_toggle?(arg)
11
+ next if set_options_for(arg, args, obj.options) || set_toggles_for(arg, obj.toggles)
12
+ elsif set_argument_for(arg, obj.arguments)
13
+ next
14
+ end
15
+ end
16
+ args = args_to_keep
17
+ end
18
+
19
+ def sub_command?
20
+ false
21
+ end
22
+
23
+ def hidden?
24
+ false
25
+ end
26
+
27
+ def assign_toggles_from(toggles)
28
+ toggles.each do |toggle|
29
+ name = toggle.normalised_attribute_name.to_sym
30
+ method_name = "#{name}?"
31
+ instance.instance_variable_set(:"@#{name}", toggle.value)
32
+ $stderr.puts "WARN: Overwrting existing method '#{name}'.." if instance.respond_to?(name)
33
+ instance.define_singleton_method(method_name) { toggle.value }
34
+ end
35
+ end
36
+
37
+ def assign_options_from(parameters)
38
+ create_variable_and_method_from(parameters)
39
+ end
40
+
41
+ def assign_arguments_from(parameters)
42
+ create_variable_and_method_from(parameters)
43
+ end
44
+
45
+ def create_variable_and_method_from(parameters)
46
+ parameters.each do |param|
47
+ name = param.normalised_attribute_name.to_sym
48
+ instance.instance_variable_set(:"@#{name}", param.value)
49
+ $stderr.puts "WARN: Overwrting existing method '#{name}'.." if instance.respond_to?(name)
50
+ instance.define_singleton_method(name) { param.value }
51
+ end
52
+ end
53
+
54
+ def ensure_parameters_defined!(*parameters)
55
+ captured_errors = validate_parameters!(parameters)
56
+ unless captured_errors.empty?
57
+ captured_errors.each { |e| $stderr.puts "ERROR: #{e}" }
58
+ exit(Exceptions::ERROR_EXIT_CODE)
59
+ end
60
+ end
61
+
62
+ private
63
+
64
+ def validate_parameters!(parameters)
65
+ captured_errors = []
66
+ parameters.flatten.each do |parameter|
67
+ begin
68
+ parameter.validate!
69
+ rescue Exceptions::Base => e
70
+ captured_errors << e.as_str
71
+ end
72
+ end
73
+ captured_errors
74
+ end
75
+
76
+ def set_toggles_for(arg, obj)
77
+ obj.each do |names, toggle|
78
+ next unless names.include?(arg)
79
+ action = inverse_toggle_arg?(arg) ? :disable! : :enable!
80
+ toggle.public_send(action)
81
+ return true
82
+ end
83
+ false
84
+ end
85
+
86
+ def set_options_for(arg, args, obj)
87
+ obj.each do |names, option|
88
+ next unless names.include?(arg)
89
+ option.value = args.shift
90
+ return true
91
+ end
92
+ false
93
+ end
94
+
95
+ def set_argument_for(value, obj)
96
+ obj.each do |_, argument|
97
+ next if argument.value
98
+ argument.value = value
99
+ return true
100
+ end
101
+ false
102
+ end
103
+
104
+ def available_toggles
105
+ klass.toggles.values.uniq(&:name)
106
+ end
107
+
108
+ def available_options
109
+ klass.options.values.uniq(&:name)
110
+ end
111
+
112
+ def available_arguments
113
+ klass.arguments.values.uniq(&:name)
114
+ end
115
+ end
116
+ end
117
+ end
@@ -0,0 +1,40 @@
1
+ module Brigadier
2
+ module Commands
3
+ class Command
4
+ include Base
5
+
6
+ attr_reader :instance
7
+
8
+ def initialize(instance, block)
9
+ @instance = instance
10
+ @block = block
11
+ end
12
+
13
+ def execute(args, full_args, klasses)
14
+ process_args(args, instance)
15
+
16
+ assign_toggles_from(available_toggles)
17
+ assign_options_from(available_options)
18
+ assign_arguments_from(available_arguments)
19
+
20
+ # FIXME
21
+ objs = (full_args.count == 1) ? klasses : klass
22
+ return if display_help_if_requested(objs, full_args)
23
+
24
+ ensure_parameters_defined!(available_options, available_arguments)
25
+
26
+ instance.instance_eval(&block)
27
+ end
28
+
29
+ private
30
+
31
+ attr_reader :block
32
+
33
+ # FIXME
34
+ def klass
35
+ @klass ||= instance
36
+ end
37
+
38
+ end
39
+ end
40
+ end
@@ -0,0 +1,63 @@
1
+ module Brigadier
2
+ module Commands
3
+ class SubCommand
4
+ include Base
5
+
6
+ attr_reader :name, :description
7
+
8
+ def initialize(name, description, instance, args, block)
9
+ @name = name
10
+ @description = description
11
+ @instance = instance
12
+ @args = args
13
+ @block = block
14
+ end
15
+
16
+ def display_name
17
+ aliases.join(', ')
18
+ end
19
+
20
+ def display_description
21
+ description
22
+ end
23
+
24
+ def execute(args, full_args)
25
+ block.call
26
+
27
+ process_args(args.dup, klass)
28
+
29
+ assign_toggles_from(available_toggles)
30
+ assign_options_from(available_options)
31
+ assign_arguments_from(available_arguments)
32
+
33
+ return if display_help_if_requested(klass, full_args)
34
+
35
+ ensure_parameters_defined!(available_options, available_arguments)
36
+
37
+ if (execute = klass.instance_variable_get('@execute_proc'))
38
+ instance.instance_eval(&execute)
39
+ else
40
+ raise Exceptions::ExecuteBlockMissing.new(self), 'There is no execute {} block defined'
41
+ end
42
+ end
43
+
44
+ def sub_command?
45
+ true
46
+ end
47
+
48
+ private
49
+
50
+ attr_reader :instance, :args, :block
51
+
52
+ def aliases
53
+ @aliases ||= args.fetch(:aliases, [])
54
+ end
55
+
56
+ # FIXME
57
+ def klass
58
+ @klass ||= instance.class
59
+ end
60
+
61
+ end
62
+ end
63
+ end
@@ -0,0 +1,8 @@
1
+ require 'brigadier/commands/base'
2
+ require 'brigadier/commands/command'
3
+ require 'brigadier/commands/sub_command'
4
+
5
+ module Brigadier
6
+ module Commands
7
+ end
8
+ end
@@ -0,0 +1,21 @@
1
+ module Brigadier
2
+ module Exceptions
3
+ class Base < StandardError
4
+ attr_reader :obj
5
+
6
+ def initialize(obj)
7
+ @obj = obj
8
+ end
9
+
10
+ def as_str
11
+ "%s '%s': %s" % [ parameter_type, obj.name, message ]
12
+ end
13
+
14
+ private
15
+
16
+ def parameter_type
17
+ obj.class.to_s.to_s.gsub(/^.*::/, '')
18
+ end
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,5 @@
1
+ module Brigadier
2
+ module Exceptions
3
+ class ExecuteBlockMissing < StandardError; end
4
+ end
5
+ end
@@ -0,0 +1,5 @@
1
+ module Brigadier
2
+ module Exceptions
3
+ class ValueInvalid < Base; end
4
+ end
5
+ end
@@ -0,0 +1,5 @@
1
+ module Brigadier
2
+ module Exceptions
3
+ class ValueMissing < Base; end
4
+ end
5
+ end
@@ -0,0 +1,10 @@
1
+ require 'brigadier/exceptions/base'
2
+ require 'brigadier/exceptions/value_invalid'
3
+ require 'brigadier/exceptions/value_missing'
4
+ require 'brigadier/exceptions/execute_block_missing'
5
+
6
+ module Brigadier
7
+ module Exceptions
8
+ ERROR_EXIT_CODE = 1
9
+ end
10
+ end