fuelcell 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (50) hide show
  1. checksums.yaml +15 -0
  2. data/.codeclimate.yml +12 -0
  3. data/.gitignore +13 -0
  4. data/.rspec +5 -0
  5. data/.travis.yml +15 -0
  6. data/CODE_OF_CONDUCT.md +13 -0
  7. data/Gemfile +3 -0
  8. data/LICENSE.txt +22 -0
  9. data/README.md +51 -0
  10. data/Rakefile +5 -0
  11. data/bin/console +9 -0
  12. data/bin/example.rb +9 -0
  13. data/bin/setup +7 -0
  14. data/bin/test +20 -0
  15. data/bin/world.rb +6 -0
  16. data/fuelcell.gemspec +26 -0
  17. data/lib/fuelcell/action/arg_definition.rb +36 -0
  18. data/lib/fuelcell/action/arg_results.rb +57 -0
  19. data/lib/fuelcell/action/args_manager.rb +66 -0
  20. data/lib/fuelcell/action/callable.rb +54 -0
  21. data/lib/fuelcell/action/command.rb +72 -0
  22. data/lib/fuelcell/action/not_found.rb +55 -0
  23. data/lib/fuelcell/action/opt_definition.rb +79 -0
  24. data/lib/fuelcell/action/opt_results.rb +68 -0
  25. data/lib/fuelcell/action/opts_manager.rb +80 -0
  26. data/lib/fuelcell/action/root.rb +76 -0
  27. data/lib/fuelcell/action/subcommands.rb +81 -0
  28. data/lib/fuelcell/action.rb +11 -0
  29. data/lib/fuelcell/cli.rb +89 -0
  30. data/lib/fuelcell/help/base_formatter.rb +24 -0
  31. data/lib/fuelcell/help/builder.rb +71 -0
  32. data/lib/fuelcell/help/cmds_formatter.rb +57 -0
  33. data/lib/fuelcell/help/desc_formatter.rb +21 -0
  34. data/lib/fuelcell/help/opts_formatter.rb +62 -0
  35. data/lib/fuelcell/help/usage_formatter.rb +88 -0
  36. data/lib/fuelcell/help.rb +27 -0
  37. data/lib/fuelcell/parser/arg_handler.rb +31 -0
  38. data/lib/fuelcell/parser/base_handler.rb +133 -0
  39. data/lib/fuelcell/parser/cmd_args_strategy.rb +28 -0
  40. data/lib/fuelcell/parser/ignore_handler.rb +25 -0
  41. data/lib/fuelcell/parser/opt_handler.rb +58 -0
  42. data/lib/fuelcell/parser/opt_name_handler.rb +89 -0
  43. data/lib/fuelcell/parser/opt_value_equal_handler.rb +26 -0
  44. data/lib/fuelcell/parser/parsing_strategy.rb +80 -0
  45. data/lib/fuelcell/parser/short_opt_no_space_handler.rb +54 -0
  46. data/lib/fuelcell/parser.rb +4 -0
  47. data/lib/fuelcell/shell.rb +102 -0
  48. data/lib/fuelcell/version.rb +3 -0
  49. data/lib/fuelcell.rb +114 -0
  50. metadata +148 -0
checksums.yaml ADDED
@@ -0,0 +1,15 @@
1
+ ---
2
+ !binary "U0hBMQ==":
3
+ metadata.gz: !binary |-
4
+ NmY4YWExNmViMzhhMjBkM2Y4MWQ4YzgyYWE3OTBkNzIxMDhiNzU5Yg==
5
+ data.tar.gz: !binary |-
6
+ ZTk4ZDFkYTJiMzc4MmUxNTU4NjQxODQ4ZjcwNTA4MDkxNTc3ZjU3MA==
7
+ SHA512:
8
+ metadata.gz: !binary |-
9
+ YWQ0ZWI5MDE5OWQ1YjgxMTI4MDlkZjJiODI3MGZiZDQ4ZjlmM2ZjZmNmMTk2
10
+ ZDJjNmE2NDdmMzRhM2I1MWYzODZjZDY5MjdhNjBmMWRkODI2NDRhM2I3YTM5
11
+ ODI0YjBjZGExNzlkMDhhYjdkNGY4M2FlNWM2MDllNmVkYjMwNTg=
12
+ data.tar.gz: !binary |-
13
+ YWMyY2EzMmYwYTM0ZjFhM2QxMjE5MDBmOGJmZDRkOTc0MmFiNTNkMTJmNjY0
14
+ NzRiNGU4Y2JhZTdjMWYwZDI4MWFmYzk2MDNlMzRkNmI3MmM0MDg0NTg3Zjhh
15
+ YTExODA0MzMxNzYzMDI1ZTNhYjUxZjFjMGJkMDQ0M2Y1ZjAzODU=
data/.codeclimate.yml ADDED
@@ -0,0 +1,12 @@
1
+ ---
2
+ engines:
3
+ rubocop:
4
+ enabled: true
5
+ bundler-audit:
6
+ enabled: false
7
+ ratings:
8
+ paths:
9
+ - "**.rb"
10
+
11
+ exclude_paths:
12
+ - spec/**/*
data/.gitignore ADDED
@@ -0,0 +1,13 @@
1
+ /.bundle/
2
+ /.yardoc
3
+ /_yardoc/
4
+ /coverage/
5
+ /doc/
6
+ /pkg/
7
+ /spec/reports/
8
+ /tmp/
9
+ *.bundle
10
+ *.so
11
+ .ruby-version
12
+ Gemfile.lock
13
+ examples
data/.rspec ADDED
@@ -0,0 +1,5 @@
1
+ --color
2
+ --require codeclimate-test-reporter
3
+ --require spec_helper
4
+ --require pp
5
+ --require fuelcell
data/.travis.yml ADDED
@@ -0,0 +1,15 @@
1
+ language: ruby
2
+ rvm:
3
+ - 2.2.2
4
+ before_install: gem install bundler -v 1.11
5
+ sudo: false
6
+ addons:
7
+ code_climate:
8
+ repo_token: 29cdb1e4095c85dd0a2e9a0a1264b074c6d4008bc2069706ef283e6a68364ce5
9
+ deploy:
10
+ on:
11
+ tags: true
12
+ provider: rubygems
13
+ api_key:
14
+ secure: Z4sBUqVeIuNJNKxXa+oYDxnfXlVaCAYl3f+8rWm4pKnHpLQYP1M8vj5LM3cmdHtUQiy/085zkvt5C6p2045PZ5sX3rueojoShqfvmNHgr3wYWQ2MZ3oHy3Vl6UJ3JYGoM/2wEclmqWQ49s1Zk4gnNZR4QyNZ/P4SWZ4FmJ9VmlI=
15
+
@@ -0,0 +1,13 @@
1
+ # Contributor Code of Conduct
2
+
3
+ As contributors and maintainers of this project, we pledge to respect all people who contribute through reporting issues, posting feature requests, updating documentation, submitting pull requests or patches, and other activities.
4
+
5
+ We are committed to making participation in this project a harassment-free experience for everyone, regardless of level of experience, gender, gender identity and expression, sexual orientation, disability, personal appearance, body size, race, ethnicity, age, or religion.
6
+
7
+ Examples of unacceptable behavior by participants include the use of sexual language or imagery, derogatory comments or personal attacks, trolling, public or private harassment, insults, or other unprofessional conduct.
8
+
9
+ Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct. Project maintainers who do not follow the Code of Conduct may be removed from the project team.
10
+
11
+ Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by opening an issue or contacting one or more of the project maintainers.
12
+
13
+ This Code of Conduct is adapted from the [Contributor Covenant](http://contributor-covenant.org), version 1.0.0, available at [http://contributor-covenant.org/version/1/0/0/](http://contributor-covenant.org/version/1/0/0/)
data/Gemfile ADDED
@@ -0,0 +1,3 @@
1
+ source 'https://rubygems.org'
2
+ gemspec
3
+ gem "codeclimate-test-reporter", group: :test, require: nil
data/LICENSE.txt ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2014 Robert Scott-Buccleuch
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,51 @@
1
+ # Fuelcell
2
+ [![Code Climate](https://codeclimate.com/github/engine8/fuelcell/badges/gpa.svg)](https://codeclimate.com/github/engine8/fuelcell)
3
+ [![Test Coverage](https://codeclimate.com/github/engine8/fuelcell/badges/coverage.svg)](https://codeclimate.com/github/engine8/fuelcell/coverage)
4
+ [![Build Status](https://travis-ci.org/engine8/fuelcell.svg?branch=master)](https://travis-ci.org/engine8/fuelcell)
5
+
6
+ ## Description
7
+ Fuelcell is tool for parsing command line arguments & options, allowing you to
8
+ concentrate more on your application and less on the logic needed to interface
9
+ with your users through the command line. It handles mapping arguments to
10
+ executable actions, defining options & arguments, self documenting help system,
11
+ through a dsl that is small and simple to learn.
12
+
13
+ ## Installation
14
+
15
+ Add this line to your application's Gemfile:
16
+
17
+ ```ruby
18
+ gem 'fuelcell'
19
+ ```
20
+
21
+ And then execute:
22
+
23
+ $ bundle
24
+
25
+ Or install it yourself as:
26
+
27
+ $ gem install fuelcell
28
+
29
+ ## Usage
30
+ ```ruby
31
+ require 'fuelcell'
32
+
33
+ Fuelcell.start(ARGV.dup) do
34
+ desc 'this is a basic hello world app'
35
+ arg 'name', default: 'World'
36
+ run ->(opts, args, shell) {
37
+ shell.puts "Hello #{args.name}"
38
+ }
39
+ end
40
+ ```
41
+
42
+ ## Development
43
+
44
+ After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake false` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
45
+
46
+ To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org).
47
+
48
+ ## Contributing
49
+
50
+ Bug reports and pull requests are welcome on GitHub at https://github.com/[USERNAME]/fuelcell. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the [Contributor Covenant](contributor-covenant.org) code of conduct.
51
+
data/Rakefile ADDED
@@ -0,0 +1,5 @@
1
+ require "bundler/gem_tasks"
2
+ require "rspec/core/rake_task"
3
+
4
+ RSpec::Core::RakeTask.new(:spec)
5
+ task default: :spec
data/bin/console ADDED
@@ -0,0 +1,9 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require "bundler/setup"
4
+ require "fuelcell"
5
+
6
+ # You can add fixtures and/or initialization code here to make experimenting
7
+ # with your gem easier. You can also use a different console, if you like.
8
+ require "pry"
9
+ Pry.start
data/bin/example.rb ADDED
@@ -0,0 +1,9 @@
1
+ Fuelcell.define 'hello' do
2
+ require_relative 'world'
3
+ desc 'say hello to the world'
4
+ opt 'name|n', banner: 'name to say hello to', required: true
5
+ opt 'f|foo', banner: 'foo bar elements'
6
+ run ->(opts, args, shell) {
7
+ shell.puts 'hello example'
8
+ }
9
+ end
data/bin/setup ADDED
@@ -0,0 +1,7 @@
1
+ #!/bin/bash
2
+ set -euo pipefail
3
+ IFS=$'\n\t'
4
+
5
+ bundle install
6
+
7
+ # Do any other automated setup that you need to do here
data/bin/test ADDED
@@ -0,0 +1,20 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'pp'
4
+ require "bundler/setup"
5
+ require "fuelcell"
6
+
7
+ Fuelcell.start(ARGV.dup, backtrace: true) do
8
+ require_relative 'example'
9
+ desc 'this is an example of how a commands work with fuelcell'
10
+ opt 'all|a', banner: 'all of something'
11
+ arg 'foo', required: true
12
+ run->(opts, args, shell) {
13
+ shell.puts "testing #{args.foo}"
14
+ }
15
+ command 'fiz' do
16
+ run ->(opts, args, shell) {
17
+ shell.puts 'called by options'
18
+ }
19
+ end
20
+ end
data/bin/world.rb ADDED
@@ -0,0 +1,6 @@
1
+ Fuelcell.define 'hello world' do
2
+ desc 'the world is saying hello'
3
+ run ->(opts, args, shell) {
4
+ shell.puts 'world hello example'
5
+ }
6
+ end
data/fuelcell.gemspec ADDED
@@ -0,0 +1,26 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'fuelcell/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "fuelcell"
8
+ spec.version = Fuelcell::VERSION
9
+ spec.authors = ["Robert Scott-Buccleuch"]
10
+ spec.email = ["rsb.code@gmail.com"]
11
+
12
+ spec.description = %q{framework which simplifies working with the command-line.}
13
+ spec.summary = spec.description
14
+ spec.homepage = "https://github.com/rsb/fuelcell"
15
+ spec.license = "MIT"
16
+
17
+ spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(spec)/}) }
18
+ spec.bindir = "exe"
19
+ spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
20
+ spec.require_paths = ["lib"]
21
+
22
+ spec.add_development_dependency "bundler", "~> 1.10"
23
+ spec.add_development_dependency "rake", "~> 10.0"
24
+ spec.add_development_dependency "pry", "~> 0.10"
25
+ spec.add_development_dependency "rspec", "~> 3.3.0"
26
+ end
@@ -0,0 +1,36 @@
1
+ module Fuelcell
2
+ module Action
3
+ class ArgDefinition
4
+ NO_DEFAULT_ASSIGNED = '__fuelcell_no_default_assigned__'
5
+ attr_reader :name, :type, :default, :required, :banner
6
+
7
+ alias_method :required?, :required
8
+
9
+ def initialize(text, config = {})
10
+ @name = text.to_s
11
+ @required = config[:required] == true ? true : false
12
+ @type = validate_type(config[:type])
13
+ @default = config.fetch(:default) { NO_DEFAULT_ASSIGNED }
14
+ @banner = config[:banner] || ''
15
+ end
16
+
17
+ def default?
18
+ @default == NO_DEFAULT_ASSIGNED ? false : true
19
+ end
20
+
21
+ private
22
+
23
+ def validate_type(value)
24
+ case value.to_s.to_sym
25
+ when :string, :text, :"" then :string
26
+ when :number, :numeric then :numeric
27
+ when :boolean, :bool then :bool
28
+ when :hash then :hash
29
+ when :array then :array
30
+ else
31
+ fail ArgumentError, "invalid type #{value}"
32
+ end
33
+ end
34
+ end
35
+ end
36
+ end
@@ -0,0 +1,57 @@
1
+ module Fuelcell
2
+ module Action
3
+ class ArgResults
4
+ extend Forwardable
5
+ attr_reader :raw
6
+ def_delegators :@raw, :empty?, :each, :join
7
+
8
+ def initialize(array, hash)
9
+ @raw, @map = validate_results(array, hash)
10
+ end
11
+
12
+
13
+ def [](key)
14
+ return raw[key] if key.is_a?(Integer)
15
+ value(key)
16
+ end
17
+
18
+ protected
19
+ attr_reader :map
20
+
21
+ def method_missing(method, *args, &_block)
22
+ method = method.to_s
23
+ return map.key?(method.chomp('?')) if method[-1] == '?'
24
+ value(method)
25
+ end
26
+
27
+ def value(key)
28
+ return nil unless index?(key)
29
+ raw[index(key)]
30
+ end
31
+
32
+ def index?(key)
33
+ map.key?(key)
34
+ end
35
+
36
+ def index(key)
37
+ map[key]
38
+ end
39
+
40
+ private
41
+
42
+ def validate_results(array, hash)
43
+ hash.each do |(key, value)|
44
+ unless value.is_a?(Integer)
45
+ fail ArgumentError, "hash value for #{key} must be an integer"
46
+ end
47
+
48
+ unless array.at(value)
49
+ fail ArgumentError,
50
+ "arg definition #{key} does not point to value in args array"
51
+ end
52
+ end
53
+ [array, hash]
54
+ end
55
+ end
56
+ end
57
+ end
@@ -0,0 +1,66 @@
1
+ module Fuelcell
2
+ module Action
3
+ # Used by the Command to manage adding args from its dsl. It is also
4
+ # used during arg parsing to find args, or check if any required args
5
+ # have been missed
6
+ class ArgsManager
7
+ attr_reader :args
8
+ extend Forwardable
9
+
10
+ def_delegators :@args, :each, :each_with_index, :empty?
11
+
12
+ def initialize
13
+ @args = []
14
+ end
15
+
16
+ def args?
17
+ !empty?
18
+ end
19
+
20
+ def required
21
+ args.select { |arg| arg.required? }
22
+ end
23
+ alias_method :required_args, :required
24
+
25
+ def missing(names)
26
+ list = []
27
+ args.select do |arg|
28
+ list << arg if arg.required? && !names.include?(arg.name)
29
+ end
30
+ return [] if list.empty?
31
+
32
+ yield list if block_given?
33
+ list
34
+ end
35
+
36
+ def add(arg, config = {})
37
+ arg = create(arg, config) if arg.is_a?(String)
38
+ args.each do |item|
39
+ if item.name == arg.name
40
+ fail "can not add arg: duplicate exists with name #{arg.name}"
41
+ end
42
+ end
43
+ args << arg
44
+ end
45
+ alias_method :arg, :add
46
+
47
+ def remove(name)
48
+ # looks like an arg definition so lets use it's name
49
+ name = name.name if name.respond_to?(:name)
50
+ args.delete_if {|arg| arg.name == name}
51
+ end
52
+
53
+ def find(name)
54
+ target = false
55
+ args.each {|arg| target = arg if arg.name == name }
56
+ target
57
+ end
58
+ alias_method :find_arg, :find
59
+ alias_method :[], :find
60
+
61
+ def create(name, config = {})
62
+ ArgDefinition.new(name, config)
63
+ end
64
+ end
65
+ end
66
+ end
@@ -0,0 +1,54 @@
1
+ module Fuelcell
2
+ module Action
3
+ module Callable
4
+ # Both getter and setting for callable object. This what the cli will
5
+ # execute when this command is found.
6
+ #
7
+ # @param value [Object] any object that implements :call
8
+ # @return [Object]
9
+ def callable(value = nil)
10
+ return @callable if value.nil?
11
+
12
+ unless value.respond_to?(:call)
13
+ fail ArgumentError, 'callable must implement :call'
14
+ end
15
+
16
+ @callable = value
17
+ end
18
+ alias_method :run, :callable
19
+
20
+ def callable?
21
+ callable.respond_to?(:call)
22
+ end
23
+ alias_method :runnable?, :callable?
24
+
25
+ # Executes this command.
26
+ #
27
+ # @param opts [Hash] processed opts from the cli parser
28
+ # @param args [Array] processed args from the cli parser
29
+ # @param shell [Fuelcell::Shell] IO abstraction
30
+ # @return [Integer] the exit code
31
+ def call(opts, args, shell)
32
+ fail 'command is not be called, callable not assigned' unless callable?
33
+ begin
34
+ cast_exit_code callable.call(opts, args, shell)
35
+ rescue StandardError => e
36
+ shell.exception e
37
+ end
38
+ end
39
+
40
+ protected
41
+
42
+ def cast_exit_code(code)
43
+ case code
44
+ when 0...255 then code
45
+ when nil, 0, '0', true then 0
46
+ when false, 1, '1' then 1
47
+ else
48
+ fail "command #{name} execution return code #{code} could " \
49
+ 'not be interpreted as an exit code'
50
+ end
51
+ end
52
+ end
53
+ end
54
+ end
@@ -0,0 +1,72 @@
1
+ module Fuelcell
2
+ module Action
3
+ # Represents the action you want to perform. It also holds a list of option
4
+ # definitions used by the parser, along with meta data used by the help
5
+ # system and callable which is any object that implements call, this is
6
+ # your action.
7
+ class Command
8
+ attr_reader :name, :opts, :args
9
+ extend Forwardable
10
+ include Subcommands
11
+ include Callable
12
+
13
+ delegate empty?: :subcommands
14
+ def_delegators :@opts, :find_opt, :opt, :missing_opts
15
+ def_delegators :@args, :find_arg, :arg, :missing_args
16
+
17
+ # Every command initializes with only its name set expecting the dsl
18
+ # to finish assigning the rest of its properties
19
+ #
20
+ # @param name [String]
21
+ def initialize(name)
22
+ @name = name.to_s
23
+ @usage = nil
24
+ @desc = nil
25
+ @opts = OptsManager.new
26
+ @args = ArgsManager.new
27
+ end
28
+
29
+ # This will assign both usage text and description, but when called
30
+ # with no args it will get the usage
31
+ #
32
+ # @param text [String]
33
+ # @param desc_text [String]
34
+ # @return [String]
35
+ def usage(text = nil, desc_text = nil)
36
+ return @usage if text.nil?
37
+ desc(desc_text) unless desc_text.nil?
38
+ @usage = text
39
+ end
40
+
41
+ # Both getting and setter for description
42
+ #
43
+ # @param text [String]
44
+ # @return [String]
45
+ def desc(text = nil)
46
+ return @desc if text.nil?
47
+ @desc = text
48
+ end
49
+
50
+ # Allows a command to add subcommands to itself
51
+ #
52
+ # @param key [String]
53
+ # @yield instance_eval into Fuelcell::Command
54
+ # @return Fuelcell::Command
55
+ def command(key, &block)
56
+ cmd = Command.new(key)
57
+ cmd.instance_eval(&block)
58
+ add cmd
59
+ end
60
+
61
+ # Allows all the global option definitions from this command hierarchy
62
+ # to be add to the command given
63
+ #
64
+ # @param cmd [Fuelcell::Action::Command]
65
+ # @return [Fuelcell::Action::Command]
66
+ def add_global_options(cmd)
67
+ global_options.each { |_key, opt_definition| cmd.opt opt_definition }
68
+ cmd
69
+ end
70
+ end
71
+ end
72
+ end
@@ -0,0 +1,55 @@
1
+ module Fuelcell
2
+ module Action
3
+ # Null Object used to indicate a command has not been found
4
+ class NotFound < Command
5
+ def initialize(cmd_args)
6
+ super(validate_cmd_args(cmd_args))
7
+
8
+ @callable = command_not_found_action
9
+ @usage = ''
10
+ @desc = 'command not found command'
11
+ end
12
+
13
+ def usage(_value = nil)
14
+ @usage
15
+ end
16
+
17
+ def desc(_value = nil)
18
+ @desc
19
+ end
20
+
21
+ def callable(_value = nil)
22
+ @callable
23
+ end
24
+
25
+ def command(key, &block)
26
+ cmd = Command.new(key)
27
+ cmd.instance_eval(&block)
28
+ nil
29
+ end
30
+
31
+ def opt(_name, _config = {})
32
+ end
33
+
34
+ def <<(_cmd)
35
+ end
36
+
37
+ private
38
+
39
+ def validate_cmd_args(args)
40
+ args = args.is_a?(String) ? [args] : args
41
+ unless args.respond_to?(:join)
42
+ fail ArgumentError, 'cmd_args must implement join'
43
+ end
44
+ args.join(' ')
45
+ end
46
+
47
+ def command_not_found_action
48
+ lambda do |_opts, _args, shell|
49
+ shell.error "command #{name} not found"
50
+ return 1
51
+ end
52
+ end
53
+ end
54
+ end
55
+ end
@@ -0,0 +1,79 @@
1
+ require 'fuelcell/parser/opt_name_handler'
2
+
3
+ module Fuelcell
4
+ module Action
5
+ # Responsible for defining all the information about an option so that the
6
+ # parser will be able to find it and its values when processing the command
7
+ # line.
8
+ class OptDefinition
9
+
10
+ include Action::Callable
11
+ NO_DEFAULT_ASSIGNED = '__fuelcell_no_default_assigned__'
12
+ attr_reader :name, :long, :short, :type, :default, :names, :required,
13
+ :cli_labels, :cli_names, :flag, :banner, :global, :cmd_path
14
+
15
+ alias_method :flag?, :flag
16
+ alias_method :required?, :required
17
+ alias_method :global?, :global
18
+
19
+ def initialize(text, config = {})
20
+ initialize_names(text)
21
+ @flag = config[:flag] == true ? true : false
22
+ @required = config[:required] == true ? true : false
23
+ @global = config[:global] == true ? true : false
24
+ @type = validate_type(config[:type])
25
+ @default = config.fetch(:default) { NO_DEFAULT_ASSIGNED }
26
+ @banner = config[:banner] || ''
27
+ @cmd_path = config[:cmd_path]
28
+ callable config[:run] if config.key?(:run)
29
+ end
30
+
31
+ def default?
32
+ @default == NO_DEFAULT_ASSIGNED ? false : true
33
+ end
34
+
35
+ def name?(value)
36
+ names.include?(value)
37
+ end
38
+
39
+ def cmd_path?
40
+ !cmd_path.nil?
41
+ end
42
+
43
+ private
44
+
45
+ def initialize_names(text)
46
+ @name, @long, @short = Parser::OptNameHandler.new.call(text)
47
+ @cli_labels = []
48
+ @names = [name]
49
+ initialize_short_name(short) if short
50
+ initialize_long_name(long) if long
51
+ @cli_names = cli_labels.join(' ')
52
+ end
53
+
54
+ def initialize_long_name(long_name)
55
+ label = "--#{long_name}"
56
+ @cli_labels << label
57
+ @names += [long_name, label]
58
+ end
59
+
60
+ def initialize_short_name(short_name)
61
+ label = "-#{short_name}"
62
+ @cli_labels << label
63
+ @names += [short_name, label]
64
+ end
65
+
66
+ def validate_type(value)
67
+ case value.to_s.to_sym
68
+ when :string, :text, :"" then :string
69
+ when :number, :numeric then :numeric
70
+ when :boolean, :bool then :bool
71
+ when :hash then :hash
72
+ when :array then :array
73
+ else
74
+ fail ArgumentError, "invalid type #{value}"
75
+ end
76
+ end
77
+ end
78
+ end
79
+ end