l43_xargs 0.1.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 ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 6cdd350e54ca66983f13d1e33b3e3e18894f353e4c3fe03a219d30ce1fd6a2d0
4
+ data.tar.gz: 49af947748b25d788161948d18d37025a27b638ff93c27c3d54dbb2e12ae5df3
5
+ SHA512:
6
+ metadata.gz: daba987a66ff981117e87d6f1d729e8d347e888b0d9bddeb4396a3c650da1fecbe7e78ce2feec6ca176852e099be512ddfd9448c2ef2647772c510ef854ecad6
7
+ data.tar.gz: 965d995dc98c035320aeb3cd4c91cd5bd4c71dff26ef081a44f9dc8b3ebb830dc38b8acb0cf27f9f4546a63f6839fba2f70dcc6d4220cb30ce3fe139a7434964
@@ -0,0 +1,23 @@
1
+ # frozen_string_literal: true
2
+
3
+ module L43
4
+ class Xargs
5
+ class AnonFlag
6
+ attr_reader \
7
+ :desc,
8
+ :name,
9
+ :value
10
+
11
+ def defaulted = !value
12
+
13
+ private
14
+ def initialize(name)
15
+ @desc = [:yellow, "anonymous flag ", :bold, name.inspect]
16
+ @name = name
17
+ @value = true
18
+ end
19
+
20
+ end
21
+ end
22
+ end
23
+ # SPDX-License-Identifier: AGPL-3.0-or-later
@@ -0,0 +1,23 @@
1
+ # frozen_string_literal: true
2
+
3
+ module L43
4
+ class Xargs
5
+ class AnonKeyword
6
+
7
+ attr_reader \
8
+ :defaulted, :desc,
9
+ :name,
10
+ :value
11
+
12
+ private
13
+ def initialize(name, value)
14
+ @defaulted = false
15
+ @desc = [:yellow, "anonymous keyword ", :bold, name.inspect]
16
+ @name = name
17
+ @value = value
18
+ end
19
+
20
+ end
21
+ end
22
+ end
23
+ # SPDX-License-Identifier: AGPL-3.0-or-later
@@ -0,0 +1,33 @@
1
+ # frozen_string_literal: true
2
+
3
+ module L43
4
+ class Xargs
5
+ class Check
6
+
7
+ attr_reader :check, :desc, :name
8
+
9
+ def call(kwds)
10
+ return if check.(kwds)
11
+ errors << [:red, :bold, "ERROR: ", :reset, :yellow, "failed check: ", :cyan, _make_description, :reset]
12
+ errors.freeze
13
+ end
14
+
15
+ def errors = @__errors__ ||= []
16
+
17
+ private
18
+ def initialize(name:, desc:, &blk)
19
+ @name = name.freeze
20
+ @desc = desc.freeze
21
+ @check = blk
22
+ end
23
+
24
+ def _make_description
25
+ return desc unless name
26
+ "#{name} (#{desc})"
27
+ end
28
+
29
+
30
+ end
31
+ end
32
+ end
33
+ # SPDX-License-Identifier: AGPL-3.0-or-later
@@ -0,0 +1,16 @@
1
+ # frozen_string_literal: true
2
+
3
+ module L43
4
+ class Xargs
5
+ module Deconstruct
6
+ def deconstruct(*)
7
+ [ok?, args, errors, kwds]
8
+ end
9
+
10
+ def deconstruct_keys(*)
11
+ {ok: ok?, args:, errors:, kwds:}
12
+ end
13
+ end
14
+ end
15
+ end
16
+ # SPDX-License-Identifier: AGPL-3.0-or-later
@@ -0,0 +1,114 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'output'
4
+ require_relative 'flag'
5
+ require_relative 'keyword'
6
+ require_relative 'descriptions'
7
+
8
+ module L43
9
+ class Xargs
10
+ class DefinedArgs
11
+ include Descriptions
12
+ BadDefinition = Class.new(RuntimeError)
13
+ DuplicateDefinition = Class.new(BadDefinition)
14
+
15
+ def add_desc(desc, element, indent:)
16
+ element.add_desc([indent || 4, *desc, :reset])
17
+ end
18
+
19
+ def def_flag(long, short=nil, desc:)
20
+ flag = Flag.new(long, short, desc:)
21
+ _def_short_flag(short, flag) if short
22
+ _def_flag(long, flag)
23
+ # p(defined_kwds: _defined_kwds)
24
+ end
25
+
26
+ def def_kwd(name, short=nil, desc:, default: None, &blk)
27
+ kwd = Keyword.new(name, short, desc:, default:, &blk)
28
+ _def_short_kwd(short, kwd) if short
29
+ _def_kwd(name, kwd)
30
+ # p(defined_kwds: _defined_kwds, defined_flags: _defined_flags)
31
+ end
32
+
33
+ def get_element(name, &blk)
34
+ _defined_flags[name] ||
35
+ _defined_kwds.fetch(name, &blk)
36
+ end
37
+
38
+ def get_flag(long)
39
+ _defined_flags[long]
40
+ end
41
+
42
+ def get_flags(&blk)
43
+ _defined_flags.each(&blk)
44
+ end
45
+
46
+ def get_kwd(long)
47
+ _defined_kwds[long]
48
+ end
49
+
50
+ def get_kwds(&blk)
51
+ _defined_kwds.each(&blk)
52
+ end
53
+
54
+ def get_missing_kwds(&blk)
55
+ missing = _defined_kwds.filter { |_, kwd| kwd.required? && kwd.defaulted }
56
+ missing.each { |_, kwd| blk.(kwd) }
57
+ end
58
+
59
+ def get_short_flag(short)
60
+ _defined_short_flags[short]
61
+ end
62
+ def get_short_kwd(short)
63
+ _defined_short_kwds[short]
64
+ end
65
+
66
+ def print_help(indent: 1, newline: true, program_name: nil, sections: true, section_colors: [:bold, :green], usage: false, device: $stderr)
67
+ lines = help_description(indent:, newline:, program_name:, usage:, sections:, section_colors:)
68
+ lines.each do |line|
69
+ Output.putc(line, device:, indent:, colorize: @_colorize)
70
+ end
71
+ end
72
+
73
+ def args = @__args__ ||= []
74
+
75
+ def kwds = @__kwds__ ||= OpenStruct.new
76
+
77
+ private
78
+ def initialize(colorize:)
79
+ @_colorize = colorize
80
+ end
81
+
82
+ def _colorize? = @_colorize
83
+
84
+ def _def_flag(name, flag)
85
+ raise DuplicateDefinition, "flag #{name.inspect} already defined" if get_flag(name)
86
+ _defined_flags[name] = flag
87
+ end
88
+
89
+ def _def_kwd(name, kwd)
90
+ raise DuplicateDefinition, "keyword #{name.inspect} already defined" if get_kwd(name)
91
+ _defined_kwds.set!(name, kwd)
92
+ end
93
+
94
+ def _def_short_flag(short, flag)
95
+ raise DuplicateDefinition, "short flag #{short.inspect} already defined" if get_short_flag(short)
96
+ _defined_short_flags.set!(short, flag)
97
+ end
98
+
99
+ def _def_short_kwd(short, kwd)
100
+ raise DuplicateDefinition, "short keyword #{short.inspect} already defined" if get_short_kwd(short)
101
+ _defined_short_kwds[short] = kwd
102
+ end
103
+
104
+ def _defined_flags = @__defined_flags__ ||= OpenStruct.new
105
+
106
+ def _defined_kwds = @__defined_kwds__ ||= OpenStruct.new
107
+
108
+ def _defined_short_flags = @__defined_short_flags__ ||= OpenStruct.new
109
+
110
+ def _defined_short_kwds = @__defined_short_kwds__ ||= OpenStruct.new
111
+ end
112
+ end
113
+ end
114
+ # SPDX-License-Identifier: AGPL-3.0-or-later
@@ -0,0 +1,57 @@
1
+ # frozen_string_literal: true
2
+
3
+ module L43
4
+ class Xargs
5
+ module Descriptions
6
+ def help_description(indent: 1, newline: true, program_name: nil, sections: true, section_colors: [:bold, :green], usage: false)
7
+ flag_section =_section("Flags", indent:, newline:, sections:, section_colors:) unless _defined_flags.empty?
8
+ kwd_section = _section("Keywords", indent:, newline:, sections:, section_colors:) unless _defined_kwds.empty?
9
+ usage_section = [:bold, "usage: ", *_maybe_program_name(program_name), *_options(usage)] if usage
10
+
11
+ [
12
+ usage_section,
13
+ flag_section,
14
+ *_flag_descriptions,
15
+ kwd_section,
16
+ *_kwd_descriptions,
17
+ ].compact
18
+ end
19
+
20
+ private
21
+ def _flag_descriptions
22
+ _defined_flags.inject([]) do |result, (_, flag)|
23
+ [*result, *flag.full_description]
24
+ end
25
+ end
26
+
27
+ def _kwd_descriptions
28
+ _defined_kwds.inject([]) do |result, (_, flag)|
29
+ [*result, *flag.full_description]
30
+ end
31
+ end
32
+
33
+ def _maybe_program_name(program_name)
34
+ return [] unless program_name
35
+ [:green, program_name + " "]
36
+ end
37
+
38
+ def _options(*usage)
39
+ case usage.flatten
40
+ in options, args
41
+ [:cyan, "[#{options}] ", :blue, "#{args}..."]
42
+ in [options]
43
+ [:cyan, "[#{options}]"]
44
+ else
45
+ []
46
+ end
47
+ end
48
+
49
+ def _section(title, indent:, newline:, sections:, section_colors:)
50
+ return unless sections
51
+ newline = newline ? [nil] : []
52
+ [*newline, indent, *Array(section_colors), title]
53
+ end
54
+ end
55
+ end
56
+ end
57
+ # SPDX-License-Identifier: AGPL-3.0-or-later
@@ -0,0 +1,55 @@
1
+ # frozen_string_literal: true
2
+
3
+ module L43
4
+ class Xargs
5
+ class Flag
6
+ attr_reader \
7
+ :additional_desc,
8
+ :desc,
9
+ :error,
10
+ :name,
11
+ :short,
12
+ :value
13
+
14
+ def add_desc(desc)
15
+ @additional_desc << desc
16
+ end
17
+
18
+ def defaulted = !value
19
+
20
+ def error? = !!@error
21
+
22
+ def full_description(indent: 3, colors: :cyan)
23
+ [
24
+ [
25
+ indent, *name_description(colors:), *desc, :reset
26
+ ],
27
+ *additional_desc
28
+ ]
29
+ end
30
+
31
+ def name_description(colors: :cyan)
32
+ formatted_name = ":#{name} "
33
+ formatted_name = ":#{short}|#{formatted_name}" if short
34
+ [*Array(colors), formatted_name, :reset]
35
+ end
36
+
37
+ def set_error!(error) = @error = error
38
+
39
+ def set_true!
40
+ @value = true
41
+ end
42
+
43
+ private
44
+ def initialize(name, short=nil, desc:)
45
+ @additional_desc = []
46
+ @desc = Array(desc)
47
+ @error = nil
48
+ @name = name
49
+ @short = short
50
+ @value = false
51
+ end
52
+ end
53
+ end
54
+ end
55
+ # SPDX-License-Identifier: AGPL-3.0-or-later
@@ -0,0 +1,80 @@
1
+ # frozen_string_literal: true
2
+
3
+ module L43
4
+ class Xargs
5
+ class Keyword
6
+ CallbackError = Class.new(RuntimeError)
7
+
8
+ attr_reader \
9
+ :additional_desc,
10
+ :callback,
11
+ :default, :defaulted, :desc,
12
+ :name,
13
+ :short,
14
+ :value
15
+
16
+ def add_desc(desc)
17
+ @additional_desc << desc
18
+ end
19
+
20
+ def description_name
21
+ prefix = short ? "#{short}:|" : ""
22
+ "#{prefix}#{name}:"
23
+ end
24
+
25
+ def default? = @__default_p__ ||= default != None
26
+
27
+ def full_description(indent: 3, colors: :cyan, important: :bold, default_colors: :dim)
28
+ [
29
+ [
30
+ indent, *name_description(colors:), *desc, *_default_description(important:, default_colors:)
31
+ ],
32
+ *additional_desc
33
+ ]#.tap { p it }
34
+ end
35
+
36
+ def name_description(colors: :cyan)
37
+ formatted_name = "#{name}: "
38
+ formatted_name = "#{short}:|#{formatted_name}" if short
39
+ [*Array(colors), formatted_name, :bold, :blue, "<value> ", :reset]
40
+ end
41
+
42
+ def required? = default == None
43
+
44
+ def set_value!(value)
45
+ @defaulted = false
46
+ value = callback.(value) if callback
47
+ @value = value
48
+ :ok
49
+ rescue RuntimeError => re
50
+ [:error, re.class, re.message]
51
+ rescue ArgumentError => ae
52
+ [:error, ArgumentError, ae.message]
53
+ end
54
+
55
+ private
56
+ def initialize(name, short=nil, desc:, default: None, &blk)
57
+ @callback = blk
58
+ @default = default
59
+ @defaulted = true
60
+ @desc = Array(desc)
61
+ @name = name
62
+ @short = short
63
+ @value = default
64
+
65
+ @additional_desc = []
66
+ end
67
+
68
+
69
+ def _default_description(important:, default_colors:)
70
+ if default?
71
+ [:reset, *Array(default_colors), " (defaults to: ", :reset, default.inspect, :dim, ")", :reset]
72
+ else
73
+ [:reset, *Array(important), " REQUIRED", :reset]
74
+ end
75
+ end
76
+
77
+ end
78
+ end
79
+ end
80
+ # SPDX-License-Identifier: AGPL-3.0-or-later
@@ -0,0 +1,28 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'ostruct'
4
+ require 'l43/core/forwarder'
5
+ class OpenStruct
6
+ extend L43::Core::Forwarder
7
+ forward_all :deconstruc_keys,
8
+ :each, :empty?,
9
+ :fetch, :filter,
10
+ :inject,
11
+ :map, to: :to_h
12
+
13
+ # def deconstruct_keys(*)
14
+ # to_h
15
+ # end
16
+
17
+ # def each(&blk) = to_h.each(&blk)
18
+ # def empty? = to_h.empty?
19
+ # def filter(&blk) = to_h.filter(&blk)
20
+ # def map(&blk) = to_h.map(&blk)
21
+
22
+ def merge(**values)
23
+ self.class.new(to_h.merge(**values))
24
+ end
25
+
26
+ def set!(key, value) = self[key.to_sym] = value
27
+ end
28
+ # SPDX-License-Identifier: AGPL-3.0-or-later
@@ -0,0 +1,42 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'l43/color/output'
4
+
5
+ module L43
6
+ class Xargs
7
+ module Output extend self
8
+ include Color::Output
9
+
10
+ def putc(*chunks, indent: 1, device: $stderr, colorize: true)
11
+ expanded = _expand_chunks(chunks, indent:, colorize:)
12
+ putcol(expanded, to: device)
13
+ end
14
+
15
+ private
16
+
17
+ def _expand_chunks(*chunks, indent:, colorize:)
18
+ chunks
19
+ .flatten
20
+ .inject([]) { |result, chunk| _expand_description(result, chunk, indent:, colorize:) }
21
+ end
22
+
23
+ def _expand_description(result, element, indent:, colorize:)
24
+ case element
25
+ when nil
26
+ [*result, "\n"]
27
+ when Integer
28
+ [*result, " " * element * indent]
29
+ when Symbol
30
+ if colorize
31
+ [*result, element]
32
+ else
33
+ result
34
+ end
35
+ else
36
+ [*result, element]
37
+ end
38
+ end
39
+ end
40
+ end
41
+ end
42
+ # SPDX-License-Identifier: AGPL-3.0-or-later
@@ -0,0 +1,161 @@
1
+ # frozen_string_literal: true
2
+
3
+ module L43
4
+ class Xargs
5
+ module Parse
6
+ def _add_defaults
7
+ # require "debug"; binding.break
8
+ defined_args.get_flags do |_, flag|
9
+ _kwds.set!(flag.name, flag)
10
+ # p(name: flag.name, kwds: _kwds)
11
+ end
12
+ defined_args.get_kwds do |_, kwd|
13
+ if kwd.default != None
14
+ _kwds.set!(kwd.name, kwd)
15
+ # p(name: kwd.name, kwds: _kwds)
16
+ end
17
+ end
18
+ end
19
+
20
+ def _add_flag(flag)
21
+ flag_def = defined_args.get_flag(flag)
22
+ _errors << _colorize("undefined flag: ", :yellow, :bold, ":#{flag}", :reset) unless flag_def
23
+ if flag_def
24
+ _check_multiple_occurence(flag_def, name: flag_def.name)
25
+ flag_def.set_true!
26
+ _kwds.set!(flag, flag_def)
27
+ else
28
+ _kwds.set!(flag, AnonFlag.new(flag))
29
+ end
30
+ argv.shift
31
+ end
32
+
33
+ def _add_kwd(name)
34
+ argv.shift
35
+
36
+ kwd_def = defined_args.get_kwd(name)
37
+ _errors << _colorize("undefined keyword: ", :yellow, :bold, name.inspect, :reset) unless kwd_def
38
+
39
+ if argv.empty?
40
+ _errors << _colorize(:yellow, :bold, "missing value ", :reset, "for keyword ", name.inspect)
41
+ raise StopIteration
42
+ end
43
+
44
+ if argv.first == "::"
45
+ _errors << _colorize(:yellow, :bold, "missing value ", :reset, "for keyword ", name.inspect, " (caused by a following :: which forces the end of argument parsing)")
46
+ return
47
+ end
48
+
49
+ value = argv.shift
50
+
51
+ if kwd_def
52
+ set_kwd(kwd_def, value)
53
+ else
54
+ _kwds.set!(name, AnonKeyword.new(name, value))
55
+ end
56
+ end
57
+
58
+ def set_kwd(kwd_def, value)
59
+ case kwd_def.set_value!(value)
60
+ in :ok
61
+ _kwds.set!(kwd_def.name, kwd_def)
62
+ in :error, klass, msg
63
+ _errors << _colorize(
64
+ "callback for keyword ", :bold, :cyan, kwd_def.name.to_s + ":",
65
+ :reset, :yellow, " raised error ", :bold, klass.to_s,
66
+ :reset, " with message: ", :bold, msg
67
+ )
68
+ end
69
+ end
70
+
71
+ def _add_short_flag(flag, shift: true)
72
+ flag_def = defined_args.get_short_flag(flag)
73
+ _errors << _colorize("undefined short flag: ", :yellow, :bold, ":#{flag}", :reset) unless flag_def
74
+
75
+ if flag_def
76
+ _check_multiple_occurence(flag_def, name: flag_def.short, short: true)
77
+ flag_def.set_true!
78
+ _kwds.set!(flag_def.name, flag_def)
79
+ else
80
+ _kwds.set!(flag, AnonFlag.new(flag))
81
+ end
82
+ argv.shift if shift
83
+ end
84
+
85
+ def _add_short_kwd(short)
86
+ argv.shift
87
+
88
+ kwd_def = defined_args.get_short_kwd(short)
89
+ _errors << _colorize("undefined short keyword: ", :yellow, :bold, short.inspect, :reset) unless kwd_def
90
+
91
+ if argv.empty?
92
+ _errors << _colorize(:yellow, :bold, "missing value ", :reset, "for short keyword ", short.inspect)
93
+ raise StopIteration
94
+ end
95
+
96
+ value = argv.shift
97
+
98
+ if kwd_def
99
+ kwd_def.set_value!(value)
100
+ _kwds.set!(kwd_def.name, kwd_def)
101
+ else
102
+ _kwds.set!(short, AnonKeyword.new(short, value))
103
+ end
104
+ end
105
+
106
+ def _check_multiple_occurence(flag_def, name:, short: false)
107
+ # p(name:, value: flag_def.value, error: flag_def.error?)
108
+ return if !flag_def.value || flag_def.error?
109
+ error_msg = [:yellow, :bold, "multiple occurences of #{short ? "short " : ""}flag: ", :cyan, name.inspect]
110
+ _errors << _colorize(*error_msg)
111
+ flag_def.set_error!(error_msg)
112
+ end
113
+
114
+ def _checks!
115
+ checks.each do |check|
116
+ check.(_kwds)
117
+ check.errors.each do |error|
118
+ _errors << error
119
+ end
120
+ end
121
+ end
122
+
123
+ def _parse
124
+ _add_defaults
125
+ loop do
126
+ _parse_argv
127
+ end
128
+ _check_for_missing!
129
+ _checks!
130
+ OpenStruct.new(args: _args, errors: _errors, kwds: _kwds)
131
+ end
132
+
133
+ def _parse_argv
134
+ raise StopIteration if argv.empty?
135
+ case argv.first
136
+ when LongFlagRgx
137
+ _add_flag($1.to_sym)
138
+ when LongKwdRgx
139
+ _add_kwd($1.to_sym)
140
+ when PosixShortFlagsRgx
141
+ $1.grapheme_clusters.each do
142
+ _add_short_flag(it.to_sym, shift: false)
143
+ end
144
+ argv.shift
145
+ when StopParsing
146
+ _args.concat(argv.drop(1))
147
+ raise StopIteration
148
+ when ShortFlagRgx
149
+ _add_short_flag($1.to_sym)
150
+ when ShortKwdRgx
151
+ _add_short_kwd($1.to_sym)
152
+ else
153
+ _args << argv.first
154
+ argv.shift
155
+ end
156
+ end
157
+
158
+ end
159
+ end
160
+ end
161
+ # SPDX-License-Identifier: AGPL-3.0-or-later
@@ -0,0 +1,8 @@
1
+ # frozen_string_literal: true
2
+
3
+ module L43
4
+ class Xargs
5
+ VERSION = "0.1.0"
6
+ end
7
+ end
8
+ # SPDX-License-Identifier: AGPL-3.0-or-later
data/lib/l43/xargs.rb ADDED
@@ -0,0 +1,168 @@
1
+ # frozen_string_literal: true
2
+
3
+ # require 'l43/core/forwarder'
4
+ module L43
5
+ class Xargs
6
+ None = Object.new.freeze
7
+ end
8
+ end
9
+
10
+ require_relative 'xargs/open_struct'
11
+ require_relative 'xargs/check'
12
+ require_relative 'xargs/deconstruct'
13
+ require_relative 'xargs/defined_args'
14
+ require_relative 'xargs/anon_flag'
15
+ require_relative 'xargs/anon_keyword'
16
+ require_relative 'xargs/parse'
17
+
18
+ module L43
19
+ class Xargs
20
+ include Deconstruct
21
+ include Parse
22
+
23
+ IllegalMonitorState = Class.new(RuntimeError)
24
+ ColorizeValues = %i[always auto never]
25
+
26
+ LongFlagRgx = %r{\A:(..+)}
27
+ LongKwdRgx = %r{\A(..+):\z}
28
+ PosixShortFlagsRgx = %r{\A-(.+)\z}
29
+ ShortFlagRgx = %r{\A:(.)\z}
30
+ ShortKwdRgx = %r{\A(.):\z}
31
+ StopParsing = "::"
32
+
33
+ attr_reader :argv, :autohelp, :defined_args, :last_added, :program_name, :usage
34
+
35
+ def add_desc(*desc, indent: nil, name: nil)
36
+ if name
37
+ element = defined_args.get_element(name) do
38
+ raise IllegalMonitorState, "cannot add description for undefined flag or keyword #{name.inspect}"
39
+ end
40
+ defined_args.add_desc(desc.flatten, element, indent:)
41
+ else
42
+ raise IllegalMonitorState, "cannot add description for last added flag or keyword before adding one" unless last_added
43
+ defined_args.add_desc(desc.flatten, last_added, indent:)
44
+ end
45
+
46
+ self
47
+ end
48
+
49
+ def args = result.args
50
+
51
+ def autohelp!
52
+ def_flag(:help, :h, desc: "Shows this help and exits") unless autohelp
53
+ @autohelp = true
54
+ self
55
+ end
56
+
57
+ def def_check(name=nil, desc:, &blk)
58
+ checks << Check.new(name:, desc:, &blk)
59
+ self
60
+ end
61
+
62
+ def def_flag(name, short=nil, desc:)
63
+ @last_added = defined_args.def_flag(name, short, desc:)
64
+ self
65
+ end
66
+
67
+ def def_kwd(name, short=nil, desc:, default: None, &blk)
68
+ @last_added = defined_args.def_kwd(name, short, desc:, default:, &blk)
69
+ self
70
+ end
71
+
72
+ def errors = result.errors
73
+
74
+ def help_description(indent: 1, newline: true, sections: true, section_colors: [:bold, :green])
75
+ defined_args.help_description(indent:, newline:, program_name:, sections:, section_colors:, usage:)
76
+ end
77
+
78
+ def full_result
79
+ raise IllegalMonitorState, "must not call full_result before calling parse" unless @__full_result__
80
+ @__full_result__
81
+ end
82
+
83
+ def kwds = result.kwds
84
+
85
+ def ok? = errors.empty?
86
+
87
+ def parse(argv)
88
+ raise IllegalMonitorState, "must not call parse twice on the same instance" if @__full_result__
89
+ @argv = argv
90
+ @__full_result__ = _parse
91
+ self
92
+ end
93
+
94
+ def print_errors
95
+ _errors.each do |error|
96
+ Output.putc(error, device: $stderr, indent: 0)
97
+ end
98
+ end
99
+
100
+ def print_help(indent: 1, newline: true, program_name: nil, sections: true, section_colors: [:bold, :green], usage: false, device: $stderr)
101
+ defined_args.print_help(indent:, newline:, program_name:, sections:, section_colors:, usage:, device:)
102
+ end
103
+
104
+ def result
105
+ raise IllegalMonitorState, "must not call result before calling parse" unless @__full_result__
106
+ @__result__ ||= _result
107
+ end
108
+
109
+ def set_program_name!(program_name)
110
+ @program_name = program_name
111
+ self
112
+ end
113
+
114
+ def set_usage!(*values)
115
+ @usage = values.flatten
116
+ self
117
+ end
118
+
119
+ private
120
+ def initialize(autohelp: false, colorize: :auto, program_name: nil, usage: false, &blk)
121
+ raise ArgumentError, "keyword argument colorize is #{colorize.inspect}, not in required set: #{ColorizeValues.inspect}" unless ColorizeValues.member? colorize
122
+ raise ArgumentError, "keyword argument autohelp is #{autohelp.inspect}, but a boolean is required" unless [false, true].member? autohelp
123
+ raise ArgumentError, "blocks are ignored and therefore not supported" if blk
124
+ @colorize = colorize
125
+ @usage = usage
126
+
127
+ @program_name = program_name
128
+ @defined_args = DefinedArgs.new(colorize: _colorize?)
129
+ def_flag(:help, :h, desc: "Shows this help and exits") if autohelp
130
+ end
131
+
132
+ def _args = @__args__ ||= []
133
+
134
+ def _colorize(*chunks)
135
+ chunks.map do |chunk|
136
+ _use_chunk(chunk)
137
+ end.compact
138
+ end
139
+
140
+ def _check_for_missing!
141
+ defined_args.get_missing_kwds do |kwd|
142
+ _errors << _colorize(:red, :bold, "ERROR: ", :yellow, "the required keyword ", :cyan, kwd.description_name, :yellow, " is missing")
143
+ end
144
+ end
145
+
146
+ def checks = @__checks__ ||= []
147
+
148
+ def _colorize? = @___colorize_p__ ||= @colorize == :always || @colorize == :auto && ENV['NO_COLOR'].nil?
149
+
150
+ def _errors = @__errors__ ||= []
151
+
152
+ def _kwds = @__kwds__ ||= OpenStruct.new
153
+
154
+ def _result
155
+ kwds = full_result.kwds.map { |k, v| [k, v.value]}.to_h
156
+ full_result.merge(kwds:)
157
+ end
158
+
159
+ def _use_chunk(chunk)
160
+ if _colorize?
161
+ chunk
162
+ elsif String===chunk
163
+ chunk
164
+ end
165
+ end
166
+ end
167
+ end
168
+ # SPDX-License-Identifier: AGPL-3.0-or-later
metadata ADDED
@@ -0,0 +1,97 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: l43_xargs
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Robert Dober
8
+ bindir: bin
9
+ cert_chain: []
10
+ date: 2026-09-04 00:00:00.000000000 Z
11
+ dependencies:
12
+ - !ruby/object:Gem::Dependency
13
+ name: ostruct
14
+ requirement: !ruby/object:Gem::Requirement
15
+ requirements:
16
+ - - "~>"
17
+ - !ruby/object:Gem::Version
18
+ version: 0.6.3
19
+ type: :runtime
20
+ prerelease: false
21
+ version_requirements: !ruby/object:Gem::Requirement
22
+ requirements:
23
+ - - "~>"
24
+ - !ruby/object:Gem::Version
25
+ version: 0.6.3
26
+ - !ruby/object:Gem::Dependency
27
+ name: l43_color
28
+ requirement: !ruby/object:Gem::Requirement
29
+ requirements:
30
+ - - "~>"
31
+ - !ruby/object:Gem::Version
32
+ version: 0.3.0
33
+ type: :runtime
34
+ prerelease: false
35
+ version_requirements: !ruby/object:Gem::Requirement
36
+ requirements:
37
+ - - "~>"
38
+ - !ruby/object:Gem::Version
39
+ version: 0.3.0
40
+ - !ruby/object:Gem::Dependency
41
+ name: l43_core
42
+ requirement: !ruby/object:Gem::Requirement
43
+ requirements:
44
+ - - "~>"
45
+ - !ruby/object:Gem::Version
46
+ version: 0.2.9
47
+ type: :runtime
48
+ prerelease: false
49
+ version_requirements: !ruby/object:Gem::Requirement
50
+ requirements:
51
+ - - "~>"
52
+ - !ruby/object:Gem::Version
53
+ version: 0.2.9
54
+ description: |
55
+ A Modular Tailor Made Command Line Parser
56
+ Yet another ClParser emerging from my needs for my Ruby Tools.
57
+ General but with a opinionated Featute Set.
58
+ email: robert.dober@gmail.com
59
+ executables: []
60
+ extensions: []
61
+ extra_rdoc_files: []
62
+ files:
63
+ - lib/l43/xargs.rb
64
+ - lib/l43/xargs/anon_flag.rb
65
+ - lib/l43/xargs/anon_keyword.rb
66
+ - lib/l43/xargs/check.rb
67
+ - lib/l43/xargs/deconstruct.rb
68
+ - lib/l43/xargs/defined_args.rb
69
+ - lib/l43/xargs/descriptions.rb
70
+ - lib/l43/xargs/flag.rb
71
+ - lib/l43/xargs/keyword.rb
72
+ - lib/l43/xargs/open_struct.rb
73
+ - lib/l43/xargs/output.rb
74
+ - lib/l43/xargs/parse.rb
75
+ - lib/l43/xargs/version.rb
76
+ homepage: https://codeberg.org/lab419/l43_opt_parser
77
+ licenses:
78
+ - AGPL-3.0-or-later
79
+ metadata: {}
80
+ rdoc_options: []
81
+ require_paths:
82
+ - lib
83
+ required_ruby_version: !ruby/object:Gem::Requirement
84
+ requirements:
85
+ - - ">="
86
+ - !ruby/object:Gem::Version
87
+ version: 4.0.1
88
+ required_rubygems_version: !ruby/object:Gem::Requirement
89
+ requirements:
90
+ - - ">="
91
+ - !ruby/object:Gem::Version
92
+ version: '0'
93
+ requirements: []
94
+ rubygems_version: 4.0.19
95
+ specification_version: 4
96
+ summary: Modular Tailor Made Command Line Parser
97
+ test_files: []