argy 0.1.0 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: dff9d90b687d261bae2c0820b5ea7b7f812d472d
4
- data.tar.gz: 5543ca5b69b14891cbd8e1744df8b7b7480edcd0
3
+ metadata.gz: '01379049c1a1d66874589c09735fba37dbfbf39b'
4
+ data.tar.gz: fb593767af624cc2c3dc06ec32a8c2286fea7f9d
5
5
  SHA512:
6
- metadata.gz: 3ee7ec946a02ce9200fbf9318d708e5ae1a652092f9891050253e34b0ad628ba1aad81e0aa1431e655ebb20a1805b79d3e0800be67e9ed881cb7ad4a5c98673e
7
- data.tar.gz: 8372f49e4daca19886b4850bfd1e6f04929a81a6584af4c57babccc0a9aa561bf5eaac035147c786a555e954639fe6ad5b35b301d603514db388d91a185c21a8
6
+ metadata.gz: 3addec730a4dce220927c0518d52a1e2188fc27ff67de5ffddc89f0e91956b62dd31d7204968de26ff14b654e5b10cd9cc10f202a00f178e6a64819ce1f9b4f4
7
+ data.tar.gz: f034dc884c0b9bad616f2daedba4068cfcf1ea8adfc27862466e6afd2c80446b880e1a36e19b5a1e7bc44d588b71ce435bbf8565398da64b109dbb7942f7a381
@@ -1,18 +1,14 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- argy (0.1.0)
4
+ argy (0.2.0)
5
5
 
6
6
  GEM
7
7
  remote: https://rubygems.org/
8
8
  specs:
9
9
  coderay (1.1.2)
10
10
  diff-lcs (1.3)
11
- equatable (0.6.1)
12
11
  method_source (0.9.2)
13
- pastel (0.7.3)
14
- equatable (~> 0.6)
15
- tty-color (~> 0.5)
16
12
  pry (0.12.2)
17
13
  coderay (~> 1.1.0)
18
14
  method_source (~> 0.9.0)
@@ -30,7 +26,6 @@ GEM
30
26
  diff-lcs (>= 1.2.0, < 2.0)
31
27
  rspec-support (~> 3.9.0)
32
28
  rspec-support (3.9.0)
33
- tty-color (0.5.0)
34
29
 
35
30
  PLATFORMS
36
31
  ruby
@@ -38,7 +33,6 @@ PLATFORMS
38
33
  DEPENDENCIES
39
34
  argy!
40
35
  bundler (~> 2.0)
41
- pastel
42
36
  pry
43
37
  rake (~> 10.0)
44
38
  rspec (~> 3.0)
data/README.md CHANGED
@@ -1,8 +1,6 @@
1
1
  # Argy
2
2
 
3
- Welcome to your new gem! In this directory, you'll find the files you need to be able to package up your Ruby library into a gem. Put your Ruby code in the file `lib/argy`. To experiment with that code, run `bin/console` for an interactive prompt.
4
-
5
- TODO: Delete this and the text above, and describe your gem
3
+ Yet another command-line option parser.
6
4
 
7
5
  ## Installation
8
6
 
@@ -22,17 +20,81 @@ Or install it yourself as:
22
20
 
23
21
  ## Usage
24
22
 
25
- TODO: Write usage instructions here
23
+ Here's an example:
24
+
25
+ ```ruby
26
+ require "argy"
27
+
28
+ parser = Argy.new do |o|
29
+ o.description "Prints messages"
30
+ o.usage "example"
31
+ o.example "$ example hello"
32
+
33
+ o.argument :message, desc: "message to print", required: true
34
+
35
+ o.option :loud, type: :boolean, desc: "say the message loudly"
36
+ o.option :count, type: :integer, desc: "number of times to print", default: 1
37
+
38
+ o.on "-v", "print the verison and exit" do
39
+ puts Example::VERSION
40
+ exit
41
+ end
42
+
43
+ o.on "-h", "--help", "show this help and exit" do
44
+ puts o.help
45
+ puts o.help.section "SECTION"
46
+ puts o.help.entry "foo", desc: "bar"
47
+ exit
48
+ end
49
+ end
50
+
51
+ begin
52
+ options = parser.parse(ARGV)
53
+ message = options.message
54
+ message = message.upcase if options.loud?
55
+ options.count.times { puts message }
56
+ rescue Argy::Error => err
57
+ abort err.message
58
+ end
59
+ ```
60
+
61
+ ## Option Types
26
62
 
27
- ## Development
63
+ Argy supports the following option types:
28
64
 
29
- After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake spec` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
65
+ - `:string`
66
+ - `:boolean`
67
+ - `:integer`
68
+ - `:float`
69
+ - `:array`
70
+ - `:pathname`
71
+
72
+ However, Argy also supports custom option types. For example:
73
+
74
+ ```ruby
75
+ class NameOption
76
+ def self.call(input)
77
+ parts = input.split(" ")
78
+ raise Argy::CoersionError, "Invalid name" if parts.length != 2
79
+ new(*parts)
80
+ end
81
+
82
+ def initialize(first, last)
83
+ @first = first
84
+ @last = last
85
+ end
86
+ end
87
+
88
+ Argy.new do |o|
89
+ o.option :name, type: NameOption
90
+ end
91
+ ```
30
92
 
31
- 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).
93
+ An option type is anything that responds to `call`. So, your option type could just be a lambda.
32
94
 
33
95
  ## Contributing
34
96
 
35
- Bug reports and pull requests are welcome on GitHub at https://github.com/[USERNAME]/argy. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the [Contributor Covenant](http://contributor-covenant.org) code of conduct.
97
+ Bug reports and pull requests are welcome on GitHub at https://github.com/rzane/argy. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the [Contributor Covenant](http://contributor-covenant.org) code of conduct.
36
98
 
37
99
  ## License
38
100
 
@@ -40,4 +102,4 @@ The gem is available as open source under the terms of the [MIT License](https:/
40
102
 
41
103
  ## Code of Conduct
42
104
 
43
- Everyone interacting in the Argy project’s codebases, issue trackers, chat rooms and mailing lists is expected to follow the [code of conduct](https://github.com/[USERNAME]/argy/blob/master/CODE_OF_CONDUCT.md).
105
+ Everyone interacting in the Argy project’s codebases, issue trackers, chat rooms and mailing lists is expected to follow the [code of conduct](https://github.com/rzane/argy/blob/master/CODE_OF_CONDUCT.md).
@@ -3,16 +3,30 @@
3
3
  require "bundler/setup"
4
4
  require "argy"
5
5
 
6
- options = Argy.parse(ARGV) do |o|
6
+ parser = Argy.new do |o|
7
+ o.description "Prints messages"
7
8
  o.usage "example"
8
- o.description "A cool thing that does stuff"
9
- o.example "$ example foo"
10
- o.argument :jint, desc: "do a thing"
11
- o.option :fizz, required: true, desc: "blah"
12
- o.option :foo_bar, aliases: ["-f"], default: "jawn"
9
+ o.example "$ example hello"
10
+ o.argument :message, desc: "message to print", required: true
11
+ o.option :loud, type: :boolean, desc: "say the message loudly"
12
+ o.option :times, type: :integer, desc: "number of times to print", default: 1
13
13
  o.on "-v", "print the verison and exit" do
14
14
  puts Argy::VERSION
15
+ exit
16
+ end
17
+ o.on "-h", "--help", "show this help and exit" do
18
+ puts o.help
19
+ puts o.help.section "SECTION"
20
+ puts o.help.entry "foo", desc: "bar"
21
+ exit
15
22
  end
16
23
  end
17
24
 
18
- puts options
25
+ begin
26
+ options = parser.parse(ARGV)
27
+ message = options.message
28
+ message = message.upcase if options.loud?
29
+ options.times.times { puts message }
30
+ rescue Argy::Error => err
31
+ abort err.message
32
+ end
@@ -5,13 +5,21 @@ module Argy
5
5
  Error = Class.new(StandardError)
6
6
  CoersionError = Class.new(Error)
7
7
  ValidationError = Class.new(Error)
8
- MissingArgumentError = Class.new(Error)
8
+
9
+ class ParseError < Error
10
+ attr_reader :original
11
+
12
+ def initialize(original)
13
+ @original = original
14
+ super(original.message)
15
+ end
16
+ end
9
17
 
10
18
  def self.new(&block)
11
19
  Argy::Parser.new(&block)
12
20
  end
13
21
 
14
- def self.parse(argv, &block)
22
+ def self.parse(argv: ARGV, &block)
15
23
  new(&block).parse(argv)
16
24
  end
17
25
  end
@@ -19,6 +19,18 @@ module Argy
19
19
  out.join("\n") + "\n"
20
20
  end
21
21
 
22
+ def section(title)
23
+ bold "\n#{title}"
24
+ end
25
+
26
+ def entry(name, desc: nil, required: false, default: nil)
27
+ out = " #{name.ljust(column)}"
28
+ out += dim("#{desc} ") if desc
29
+ out += dim("(required) ") if required
30
+ out += dim("[default: #{default.inspect}]") if default
31
+ out.rstrip
32
+ end
33
+
22
34
  private
23
35
 
24
36
  def description(out)
@@ -41,7 +53,7 @@ module Argy
41
53
  end
42
54
 
43
55
  def argument(a)
44
- parameter(a.label, a.desc, a.required?, a.default)
56
+ entry(a.label, desc: a.desc, required: a.required?, default: a.default)
45
57
  end
46
58
 
47
59
  def options(out)
@@ -52,19 +64,18 @@ module Argy
52
64
  def option(o)
53
65
  label = [option_label(o.label, o.type)]
54
66
  label += o.aliases.map { |a| option_label(a, o.type) }
55
- parameter(label.join(", "), o.desc, o.required?, o.default)
67
+ entry(label.join(", "), desc: o.desc, required: o.required?, default: o.default)
56
68
  end
57
69
 
58
70
  def flags(out)
59
- out << bold("\nFLAGS")
71
+ out << bold("\nFLAGS") if parser.flags.any?
60
72
  out.concat parser.flags.map { |f, _| flag(f) }
61
- out << parameter("--help, -h", "show this help and exit")
62
73
  end
63
74
 
64
75
  def flag(flag)
65
76
  flag = flag.dup
66
77
  desc = flag.pop unless flag.last.match?(/^-/)
67
- parameter(flag.reverse.join(", "), desc)
78
+ entry(flag.reverse.join(", "), desc: desc)
68
79
  end
69
80
 
70
81
  def option_label(label, type)
@@ -72,14 +83,6 @@ module Argy
72
83
  label.start_with?("--") ? "#{label}=VALUE" : "#{label} VALUE"
73
84
  end
74
85
 
75
- def parameter(left, right, required = false, default = nil)
76
- label = " #{left.ljust(column)}"
77
- label += dim("#{right} ") if right
78
- label += dim("(required) ") if required
79
- label += dim("[default: #{default.inspect}]") if default
80
- label.rstrip
81
- end
82
-
83
86
  def bold(text)
84
87
  color? ? "\e[1m#{text}\e[0m" : text
85
88
  end
@@ -0,0 +1,38 @@
1
+ module Argy
2
+ class Options
3
+ def initialize(values)
4
+ @values = values
5
+ end
6
+
7
+ def to_h
8
+ @values
9
+ end
10
+
11
+ def [](key)
12
+ @values[key]
13
+ end
14
+
15
+ def fetch(*args, &block)
16
+ @values.fetch(*args, &block)
17
+ end
18
+
19
+ private
20
+
21
+ def respond_to_missing?(meth, *)
22
+ @values.key?(meth.to_s.sub(/\?$/, "").to_sym) || super
23
+ end
24
+
25
+ def method_missing(meth, *args)
26
+ query = meth[-1] == "?"
27
+ key = query ? meth[0..-2].to_sym : meth.to_sym
28
+
29
+ return super unless @values.key?(key)
30
+
31
+ unless args.empty?
32
+ raise ArgumentError, "wrong number of arguments (given #{args.length}, expected 0)"
33
+ end
34
+
35
+ query ? !!@values[key] : @values[key]
36
+ end
37
+ end
38
+ end
@@ -1,3 +1,4 @@
1
+ require "pathname"
1
2
  require "argy/parameter"
2
3
 
3
4
  module Argy
@@ -2,6 +2,7 @@ require "optparse"
2
2
  require "argy/help"
3
3
  require "argy/option"
4
4
  require "argy/argument"
5
+ require "argy/options"
5
6
 
6
7
  module Argy
7
8
  class Parser
@@ -52,25 +53,37 @@ module Argy
52
53
  end
53
54
 
54
55
  def default_values
55
- (arguments + options).reduce(unused_arguments: []) do |acc, opt|
56
+ parameters.reduce(unused_args: []) do |acc, opt|
56
57
  acc[opt.name] = opt.default
57
58
  acc
58
59
  end
59
60
  end
60
61
 
61
- def parse(argv)
62
+ def parse(argv, strategy: nil)
62
63
  argv = argv.dup
63
64
  values = default_values
64
-
65
65
  parser = build_parser(values)
66
- parser.parse!(argv)
66
+
67
+ case strategy
68
+ when :order
69
+ parser.order!(argv)
70
+ when :permute
71
+ parser.permute!(argv)
72
+ else
73
+ parser.parse!(argv)
74
+ end
67
75
 
68
76
  populate_arguments(values, argv)
69
- validate!(values)
77
+ Options.new validate!(values)
78
+ rescue OptionParser::ParseError => error
79
+ raise ParseError.new(error)
80
+ end
70
81
 
82
+ def validate!(values)
83
+ parameters.each do |param|
84
+ param.validate(values[param.name])
85
+ end
71
86
  values
72
- rescue OptionParser::MissingArgument => error
73
- raise MissingArgumentError, error.message
74
87
  end
75
88
 
76
89
  private
@@ -78,19 +91,13 @@ module Argy
78
91
  def populate_arguments(values, argv)
79
92
  argv.zip(arguments).each do |value, arg|
80
93
  if arg.nil?
81
- values[:unused_arguments] << value
94
+ values[:unused_args] << value
82
95
  else
83
96
  values[arg.name] = arg.coerce(value)
84
97
  end
85
98
  end
86
99
  end
87
100
 
88
- def validate!(values)
89
- parameters.each do |param|
90
- param.validate(values[param.name])
91
- end
92
- end
93
-
94
101
  def build_parser(values)
95
102
  OptionParser.new do |o|
96
103
  options.each do |opt|
@@ -102,11 +109,6 @@ module Argy
102
109
  flags.each do |flag, action|
103
110
  o.on(*flag, &action)
104
111
  end
105
-
106
- o.on("-h", "--help") do
107
- puts help
108
- exit
109
- end
110
112
  end
111
113
  end
112
114
  end
@@ -1,3 +1,3 @@
1
1
  module Argy
2
- VERSION = "0.1.0"
2
+ VERSION = "0.2.0"
3
3
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: argy
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 0.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Ray Zane
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2019-12-06 00:00:00.000000000 Z
11
+ date: 2019-12-12 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -76,6 +76,7 @@ files:
76
76
  - lib/argy/argument.rb
77
77
  - lib/argy/help.rb
78
78
  - lib/argy/option.rb
79
+ - lib/argy/options.rb
79
80
  - lib/argy/parameter.rb
80
81
  - lib/argy/parser.rb
81
82
  - lib/argy/version.rb