strop 0.2.0 → 0.4.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
  SHA256:
3
- metadata.gz: 7f104516e3a61250be80d317bb041ab59f8e39fadf0fd2b4aefe18de8af90165
4
- data.tar.gz: b55d4717c195ec9373b495b933758435eb764fd4f51073761a45456e2de47784
3
+ metadata.gz: 225cf6a25d9576df114857aab9e157c4f9d2c666f74e066bd21fc012b9a8f83d
4
+ data.tar.gz: 2dfc769e16d1dff9db71788250fedeb23973a46fc2e86633bda69d03b3afef5c
5
5
  SHA512:
6
- metadata.gz: 1e629cc1a18457b54482398d8d1578d787f57ddd182c627a076f2ce7d2be9c639be3c893734422d0a23cd2be5fa2a534c527888f1437d1474a527078f5365a63
7
- data.tar.gz: 8ef9f135caede03849470cd17ee470c8440b34838736bc100ef5c41502e41b35d7c99caa18c6f832edeeac72c9c67f6c926b03cc6d393f0679d34609ac8f112f
6
+ metadata.gz: 57a71386c4e906a3b444da5dabb81a145faef6795639e420917f20386ee75d7c4e8a1442c398ea72db413ee363f5b284ebee113b0e3875b14867c331968c8a99
7
+ data.tar.gz: a77e623a861b637d2c01e955bf984d556fdd54d4b3c8f9896d22ac8b346fb370702eb04053a1c1a922de51a050e5627e5429ecc1c568bb21f650cf28c7e8f4e5
data/README.md CHANGED
@@ -58,10 +58,11 @@ puts Strop.parse_help(help_text).to_s(:case)
58
58
  ## Result members (Array of Opt, Arg, Sep)
59
59
 
60
60
  ```ruby
61
- res.opts # all Opt objects
62
- res.args # all Arg objects
63
- res.rest # args after -- separator
64
- res["flag"] # find opt by name
61
+ res.opts # all Opt objects
62
+ res.args # all Arg objects
63
+ res.rest # args after -- separator
64
+ res["flag"] # find opt by name
65
+ res[["flag"]] # find all opts matching name
65
66
 
66
67
  opt = res.opts.first
67
68
  arg = res.args.first
@@ -73,6 +74,7 @@ opt.no? # true if --no-foo variant used
73
74
  opt.yes? # opposite of `no?`
74
75
  arg.value # positional argument
75
76
  arg.arg # same as .value, useful for pattern matching
77
+ arg.to_s # implicit string conversion (same as .value)
76
78
  Sep # -- end of options marker; Const, not instantiated
77
79
  ```
78
80
 
@@ -118,6 +120,7 @@ cmd -fVAL, --foo=VAL # attached values
118
120
  cmd -f VAL, --foo VAL # separate values
119
121
  cmd --foo val -- --bar # --bar becomes positional after --
120
122
  cmd --intermixed args and --options # flexible ordering
123
+ cmd --ver # partial matching (--ver matches --verbose if unique)
121
124
  ```
122
125
 
123
126
  ## Manual option declaration building
@@ -141,6 +144,7 @@ Optdecl["foo_bar"] # --foo_bar: but not in strings.
141
144
  ```ruby
142
145
  optlist = Optlist[optdecl1, optdecl2] # combine decls into optlist
143
146
  optlist["f"] # lookup by name
147
+ optlist["fl"] # partial match (finds "flag" if unique)
144
148
  ```
145
149
 
146
150
  ## Argument requirements
data/lib/strop/version.rb CHANGED
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Strop
4
- VERSION = "0.2.0"
4
+ VERSION = "0.4.0"
5
5
  end
data/lib/strop.rb CHANGED
@@ -6,17 +6,18 @@ require_relative "strop/version"
6
6
  # Command-line option parser that builds options from help text
7
7
  module Strop
8
8
  def self.prefix(name) = (name[1] ? "--" : "-") + name # helper for printing back option names with the right prefix
9
+ def self.name_from_symbol(name) = Symbol === name ? name.to_s.gsub(?_, ?-) : name
9
10
 
10
11
  # Option declaration: names, argument requirement, and canonical label (auto-determined)
11
12
  # Optdecl[:f, :foo, arg: :may] #=> Optdecl(names: ["f", "foo"], arg: :may, label: "foo")
12
13
  Optdecl = Data.define(:names, :arg, :label) do
13
14
  def self.[](*names, arg: nil) = new(names:, arg:) # Custom builder: Optdecl[names, ..., arg: ...]
14
15
  def initialize(names:, arg: nil)
15
- names = [*names].map{ Symbol === it ? it.to_s.gsub(?_, ?-) : it } # :foo_bar to "foo-bar" for symbols
16
- names[0] = names[0].sub(/[!?]$/, "") unless arg # opt? / opt! to opt, and... (unless arg given)
17
- arg ||= { ?? => :may, ?! => :must }[$&] || :shant # use ?/! to determine arg (unless arg given)
18
- label = names.find{ it.size > 1 } || names.first # the canonical name used to search for it
19
- %i[must may shant].member? arg or raise "invalid arg" # validate arg
16
+ names = [*names].map{ Strop.name_from_symbol it } # :foo_bar to "foo-bar" for symbols
17
+ names[0] = names[0].sub(/[!?]$/, "") unless arg # opt? / opt! to opt, and... (unless arg given)
18
+ arg ||= { ?? => :may, ?! => :must }[$&] || :shant # use ?/! to determine arg (unless arg given)
19
+ label = names.find{ it.size > 1 } || names.first # the canonical name used to search for it
20
+ %i[must may shant].member? arg or raise "invalid arg" # validate arg
20
21
  super names:, arg:, label:
21
22
  end
22
23
 
@@ -30,7 +31,18 @@ module Strop
30
31
  # Optlist[decl1, decl2] #=> [Optdecl(...), Optdecl(...)]
31
32
  class Optlist < Array # a list of Optdecls
32
33
  def self.from_help(doc) = Strop.parse_help(doc) #=> Optlist[decl, ...] # Build from help text
33
- def [](k, ...) = [String, Symbol].any?{ it === k } ? self.find{ it.names.member? k.to_s } : super(k, ...)
34
+
35
+ def [](k, ...)
36
+ case k
37
+ in String | Symbol
38
+ s = Strop.name_from_symbol k
39
+ found = find{ it.names.member? s } and return found
40
+ found, *others = select{ it.names.any?{ it.start_with? s }} if s[1]
41
+ found if found && others.empty?
42
+ else super(k, ...)
43
+ end
44
+ end
45
+
34
46
  def to_s(as=:plain)
35
47
  case as
36
48
  when :plain then join("\n")
@@ -58,6 +70,7 @@ module Strop
58
70
  Arg = Data.define :value, :arg do
59
71
  def initialize(value:) = super(value:, arg: value)
60
72
  alias to_s value
73
+ alias to_str value
61
74
  end
62
75
 
63
76
  # Parsed option with declaration, invocation name, value, and negation state. Used internally. Seen as member of Result.
@@ -73,7 +86,7 @@ module Strop
73
86
  end
74
87
 
75
88
  # Const for parsed `--` end of option markers. Seen as member of Result.
76
- Sep = :end_marker
89
+ Sep = :sep
77
90
 
78
91
  # Parse result containing options, arguments, and separators; Returned by `parse`
79
92
  # Result[opt1, arg1, Sep] #=> [Opt(...), Arg(...), Sep]
@@ -83,7 +96,8 @@ module Strop
83
96
  def opts = Result.new(select { Opt === it })
84
97
  def [](k, ...)
85
98
  case k
86
- when String, Symbol then find{ Opt === it && it.decl.names.member?(k.to_s) }
99
+ in [String | Symbol => name] then opts.select{ it.decl.names.include? Strop.name_from_symbol name }
100
+ in String | Symbol then find{ Opt === it && it.decl.names.member?(Strop.name_from_symbol k) }
87
101
  else super(k, ...)
88
102
  end
89
103
  end
@@ -123,7 +137,7 @@ module Strop
123
137
  res = Result.new
124
138
  ctx = :top
125
139
  name, token, opt = nil
126
- rx_value = /\A[^-]|\A\z/ # not an opt
140
+ rx_value = /\A[^-]|\A-?\z/ # not an opt
127
141
  loop do
128
142
  case ctx
129
143
  in :end then return res.concat tokens.map{ Arg[it] } # opt parsing ended, rest is positional args
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: strop
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.0
4
+ version: 0.4.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Caio Chassot