l43_opt_parser 0.0.1
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 +7 -0
- data/lib/l43/opt_parser/errors.rb +7 -0
- data/lib/l43/opt_parser/flag.rb +33 -0
- data/lib/l43/opt_parser/keyword.rb +46 -0
- data/lib/l43/opt_parser/version.rb +8 -0
- data/lib/l43/opt_parser.rb +162 -0
- metadata +61 -0
checksums.yaml
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
---
|
|
2
|
+
SHA256:
|
|
3
|
+
metadata.gz: 63be9d1fa069240f7ef6fdd36805bb3af88c50519543465170bfb15dcd1af069
|
|
4
|
+
data.tar.gz: f54d8f9209b79139f896e8453e78010de27dd3bdd00c0aa6aa6db3f0713c8e4a
|
|
5
|
+
SHA512:
|
|
6
|
+
metadata.gz: fb4bf372fe886ef383b136b964499dbfc861fc6c67b7b58343eb63651b0ecf1b4235e66aacf865d0465f807386c4d330b844463af9c414351f598bf839a4072c
|
|
7
|
+
data.tar.gz: c332e0cb1dda8032e5636d9c96b5fc99d43f9c588140e3561ac48f0e7ebe7d6d7128bea88b67b968f90dc1a585c48574ad0dc77a1eedf4388adaec5833cce99e
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
module L43
|
|
3
|
+
class OptParser
|
|
4
|
+
class Flag
|
|
5
|
+
attr_reader :multiple, :name
|
|
6
|
+
|
|
7
|
+
def on_multiple(&blk)
|
|
8
|
+
@on_multiple = blk
|
|
9
|
+
self
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
def update(value, old_value)
|
|
13
|
+
if old_value && !multiple
|
|
14
|
+
[:error, "flag :#{name} has already been specified but is not a multiple flag"]
|
|
15
|
+
elsif multiple
|
|
16
|
+
[:ok, @on_multiple.(old_value, value)]
|
|
17
|
+
else
|
|
18
|
+
[:ok, true]
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
private
|
|
23
|
+
def initialize(name, multiple: false)
|
|
24
|
+
@name = name
|
|
25
|
+
@multiple = multiple
|
|
26
|
+
on_multiple do |old, value|
|
|
27
|
+
old ? old.succ : value
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
# SPDX-License-Identifier: AGPL-3.0-or-later
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module L43
|
|
4
|
+
class OptParser
|
|
5
|
+
class Keyword
|
|
6
|
+
attr_reader :initializer, :multiple, :name, :type
|
|
7
|
+
|
|
8
|
+
def on_multiple(&blk)
|
|
9
|
+
@on_multiple = blk
|
|
10
|
+
self
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
def update(value, old_value)
|
|
14
|
+
if old_value && !multiple
|
|
15
|
+
[:error, "keyword #{name} has already been specified but is not a multiple keyword"]
|
|
16
|
+
elsif old_value
|
|
17
|
+
value = make_value(value)
|
|
18
|
+
[:ok, @on_multiple.(old_value, value)]
|
|
19
|
+
elsif multiple
|
|
20
|
+
[:ok, [make_value(value)]]
|
|
21
|
+
else
|
|
22
|
+
[:ok, make_value(value)]
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
private
|
|
27
|
+
def initialize(name, multiple: false, type: String, &initializer)
|
|
28
|
+
@initializer = initializer
|
|
29
|
+
@name = name
|
|
30
|
+
@multiple = multiple
|
|
31
|
+
@type = type
|
|
32
|
+
on_multiple do |old, value|
|
|
33
|
+
old ? [*old, value] : value
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
def make_value(value)
|
|
38
|
+
value = type.new(value)
|
|
39
|
+
value = initializer.(value) if initializer
|
|
40
|
+
multiple
|
|
41
|
+
value
|
|
42
|
+
end
|
|
43
|
+
end
|
|
44
|
+
end
|
|
45
|
+
end
|
|
46
|
+
# SPDX-License-Identifier: AGPL-3.0-or-later
|
|
@@ -0,0 +1,162 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'ostruct'
|
|
4
|
+
require_relative 'opt_parser/errors'
|
|
5
|
+
require_relative 'opt_parser/flag'
|
|
6
|
+
require_relative 'opt_parser/keyword'
|
|
7
|
+
|
|
8
|
+
module L43
|
|
9
|
+
class OptParser
|
|
10
|
+
|
|
11
|
+
FlagRgx = /\A:(.*)/
|
|
12
|
+
KeywordRgx = /(.*):\z/
|
|
13
|
+
|
|
14
|
+
# Constraints
|
|
15
|
+
# -----------
|
|
16
|
+
def flag(name, multiple: false)
|
|
17
|
+
flags.merge!(symbolize(name) => Flag.new(symbolize(name), multiple:)) { |*|
|
|
18
|
+
raise DuplicateFlagDefinition, "flag :#{name} is already defined"
|
|
19
|
+
}
|
|
20
|
+
@constrained = true
|
|
21
|
+
self
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
def keyword(name, multiple: false, type: String, &initializer)
|
|
25
|
+
keywords.merge!(name => Keyword.new(name, multiple:, type:, &initializer)) { |*|
|
|
26
|
+
raise DuplicateKeywordDefinition, "keyword :#{name} is already defined"
|
|
27
|
+
}
|
|
28
|
+
@constrained = true
|
|
29
|
+
self
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
# Business Logic
|
|
33
|
+
# --------------
|
|
34
|
+
def parse(arguments)
|
|
35
|
+
reset_data!
|
|
36
|
+
@arguments = arguments
|
|
37
|
+
parse_arguments
|
|
38
|
+
|
|
39
|
+
OpenStruct.new(args:, errors:, kwds:, ok?: errors.empty?).freeze
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
private
|
|
43
|
+
# Permissions
|
|
44
|
+
# -----------
|
|
45
|
+
def allowed_flag?(flag)
|
|
46
|
+
return true unless constrained?
|
|
47
|
+
flags.fetch(flag, false)
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
def allowed_kwd?(kwd)
|
|
51
|
+
return true unless constrained?
|
|
52
|
+
keywords.fetch(kwd, false)
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
def check_kwd(kwd, value)
|
|
56
|
+
return unless constrained?
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
# Error Handling
|
|
61
|
+
# --------------
|
|
62
|
+
def add_errors(new_errors) = errors.push(*new_errors)
|
|
63
|
+
|
|
64
|
+
# Business Logic
|
|
65
|
+
# --------------
|
|
66
|
+
def assign_kwd(kwd, value)
|
|
67
|
+
error = check_kwd(kwd, value)
|
|
68
|
+
return add_errors(error) if error
|
|
69
|
+
keyword = get_keyword(kwd)
|
|
70
|
+
case keyword.update(value, kwds[kwd])
|
|
71
|
+
in :ok, value
|
|
72
|
+
kwds.merge!(kwd => value)
|
|
73
|
+
in :error, message
|
|
74
|
+
add_errors(message)
|
|
75
|
+
end
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
def cast_value(_kwd, value)
|
|
79
|
+
return value unless constrained?
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
def get_flag(flag)
|
|
83
|
+
flags.fetch(flag) do
|
|
84
|
+
flags[flag] = Flag.new(flag, multiple: true)
|
|
85
|
+
end
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
def get_keyword(kwd)
|
|
89
|
+
keywords.fetch(kwd) do
|
|
90
|
+
keywords[kwd] = Keyword.new(kwd, multiple: true)
|
|
91
|
+
end
|
|
92
|
+
end
|
|
93
|
+
|
|
94
|
+
def parse_argument
|
|
95
|
+
case @arguments.first
|
|
96
|
+
when nil
|
|
97
|
+
return
|
|
98
|
+
when '::'
|
|
99
|
+
args.push(*@arguments.drop(1))
|
|
100
|
+
return
|
|
101
|
+
when FlagRgx
|
|
102
|
+
parse_flag($1.to_sym)
|
|
103
|
+
when KeywordRgx
|
|
104
|
+
parse_kwd($1.to_sym)
|
|
105
|
+
else
|
|
106
|
+
args << @arguments.first
|
|
107
|
+
1
|
|
108
|
+
end
|
|
109
|
+
end
|
|
110
|
+
|
|
111
|
+
def parse_arguments
|
|
112
|
+
loop do
|
|
113
|
+
count = parse_argument
|
|
114
|
+
return unless count
|
|
115
|
+
@arguments = @arguments.drop(count)
|
|
116
|
+
end
|
|
117
|
+
end
|
|
118
|
+
|
|
119
|
+
def parse_flag(flag)
|
|
120
|
+
add_errors("undefined flag: :#{flag}") unless allowed_flag?(flag)
|
|
121
|
+
|
|
122
|
+
defined_flag = get_flag(flag)
|
|
123
|
+
case defined_flag.update(1, kwds[flag])
|
|
124
|
+
in :ok, value
|
|
125
|
+
kwds.merge!(flag => value)
|
|
126
|
+
in :error, message
|
|
127
|
+
add_errors(message)
|
|
128
|
+
end
|
|
129
|
+
1
|
|
130
|
+
end
|
|
131
|
+
|
|
132
|
+
def parse_kwd(kwd)
|
|
133
|
+
add_errors("undefined keyword: #{kwd}:") unless allowed_kwd?(kwd)
|
|
134
|
+
case @arguments
|
|
135
|
+
in [_]
|
|
136
|
+
add_errors("keyword #{kwd}: requires value but none was given, make sure there is an argument after '#{kwd}:'")
|
|
137
|
+
in [_, value, *]
|
|
138
|
+
assign_kwd(kwd, value)
|
|
139
|
+
end
|
|
140
|
+
2
|
|
141
|
+
end
|
|
142
|
+
|
|
143
|
+
def symbolize(name) = name.to_s.gsub("-", "_").to_sym
|
|
144
|
+
|
|
145
|
+
# Data
|
|
146
|
+
# ----
|
|
147
|
+
def args = @__args__ ||= []
|
|
148
|
+
def constrained? = @constrained
|
|
149
|
+
def errors = @__errors__ ||= []
|
|
150
|
+
def kwds = @__kwds__ ||= {}
|
|
151
|
+
def flags = @__flags__ ||= {}
|
|
152
|
+
def keywords = @__keywords__ ||= {}
|
|
153
|
+
|
|
154
|
+
def reset_data!
|
|
155
|
+
@__args__ = []
|
|
156
|
+
@__errors__ = []
|
|
157
|
+
@__kwds__ = {}
|
|
158
|
+
end
|
|
159
|
+
|
|
160
|
+
end
|
|
161
|
+
end
|
|
162
|
+
# SPDX-License-Identifier: AGPL-3.0-or-later
|
metadata
ADDED
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
|
2
|
+
name: l43_opt_parser
|
|
3
|
+
version: !ruby/object:Gem::Version
|
|
4
|
+
version: 0.0.1
|
|
5
|
+
platform: ruby
|
|
6
|
+
authors:
|
|
7
|
+
- Robert Dober
|
|
8
|
+
bindir: bin
|
|
9
|
+
cert_chain: []
|
|
10
|
+
date: 2026-02-10 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
|
+
description: |
|
|
27
|
+
A highly customizable option parser, allowing for different
|
|
28
|
+
option syntax and returning custom classes' instances depending on
|
|
29
|
+
the configured options
|
|
30
|
+
email: robert.dober@gmail.com
|
|
31
|
+
executables: []
|
|
32
|
+
extensions: []
|
|
33
|
+
extra_rdoc_files: []
|
|
34
|
+
files:
|
|
35
|
+
- lib/l43/opt_parser.rb
|
|
36
|
+
- lib/l43/opt_parser/errors.rb
|
|
37
|
+
- lib/l43/opt_parser/flag.rb
|
|
38
|
+
- lib/l43/opt_parser/keyword.rb
|
|
39
|
+
- lib/l43/opt_parser/version.rb
|
|
40
|
+
homepage: https://codeberg.org/lab419/l43_opt_parser
|
|
41
|
+
licenses:
|
|
42
|
+
- AGPL-3.0-or-later
|
|
43
|
+
metadata: {}
|
|
44
|
+
rdoc_options: []
|
|
45
|
+
require_paths:
|
|
46
|
+
- lib
|
|
47
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
|
48
|
+
requirements:
|
|
49
|
+
- - ">="
|
|
50
|
+
- !ruby/object:Gem::Version
|
|
51
|
+
version: 4.0.0
|
|
52
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
53
|
+
requirements:
|
|
54
|
+
- - ">="
|
|
55
|
+
- !ruby/object:Gem::Version
|
|
56
|
+
version: '0'
|
|
57
|
+
requirements: []
|
|
58
|
+
rubygems_version: 4.0.4
|
|
59
|
+
specification_version: 4
|
|
60
|
+
summary: Extract Specs from Markdown
|
|
61
|
+
test_files: []
|