lab42_rgxargs 0.1.1 → 0.1.6
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 +4 -4
- data/lib/lab42/rgxargs.rb +109 -74
- data/lib/lab42/rgxargs/argument_matcher.rb +35 -0
- data/lib/lab42/rgxargs/checker.rb +33 -0
- data/lib/lab42/rgxargs/constrainer.rb +15 -0
- data/lib/lab42/rgxargs/error.rb +2 -0
- data/lib/lab42/rgxargs/predefined_matchers.rb +8 -8
- data/lib/lab42/rgxargs/syntax.rb +19 -0
- data/lib/lab42/rgxargs/syntax_definer.rb +34 -0
- metadata +41 -7
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 6c2b779615c5996b97aaa6fbb336adaecaba2119168d9cd6e28665bca4f26587
|
4
|
+
data.tar.gz: d1f125fb9a12342f54c3f6748d0a93c3782fc46d0abefd0330324a1ebe3aee3a
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: dab565b74468cc86dfdedcc162343fc9b85eae244d908a0422b78ef68c5cae65c49e1eb0acf8463bc0a492a645f89441c2f71438e7671eac4534aca89b19bbdf
|
7
|
+
data.tar.gz: 7bb8d96d57afeb88a720c6500dcefda5b2f8fc24e877112c0930e6062e0918b5fa304aa3816e757a1885e51567ed24c3cfec238b73d30678d6e99fe7be4b8410
|
data/lib/lab42/rgxargs.rb
CHANGED
@@ -4,116 +4,151 @@ require 'lab42/enumerable'
|
|
4
4
|
module Lab42
|
5
5
|
|
6
6
|
class Rgxargs
|
7
|
+
require_relative 'rgxargs/checker'
|
8
|
+
require_relative 'rgxargs/constrainer'
|
7
9
|
require_relative 'rgxargs/predefined_matchers'
|
10
|
+
require_relative 'rgxargs/argument_matcher'
|
11
|
+
require_relative 'rgxargs/syntax_definer'
|
12
|
+
include Checker
|
13
|
+
include Constrainer
|
14
|
+
|
8
15
|
Predefined = PredefinedMatchers
|
9
16
|
|
10
17
|
extend Forwardable
|
11
18
|
def_delegators Predefined, :list_matcher
|
12
19
|
|
13
|
-
attr_reader :args, :conversions, :defined_rules, :errors, :options, :syntaxes
|
20
|
+
attr_reader :allowed, :args, :conversions, :defaults, :defined_rules, :errors, :options, :required, :syntaxes
|
14
21
|
|
15
22
|
|
16
|
-
def add_conversion(param, conversion)
|
23
|
+
def add_conversion(param, conversion, required=nil, &block)
|
17
24
|
case conversion
|
18
25
|
when Symbol
|
19
|
-
|
26
|
+
_add_symbolic_conversion(param, conversion, required)
|
20
27
|
else
|
21
|
-
|
28
|
+
_add_proc_conversion(param, conversion, block, required)
|
22
29
|
end
|
23
30
|
end
|
24
31
|
|
25
|
-
def add_syntax(rgx, parser=nil)
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
raise ArgumentError, "#{rgx} is not a predefined syntax, use one of the following:\n\t#{Predefined.defined_names}"
|
33
|
-
end
|
32
|
+
def add_syntax(rgx, parser=nil, as: nil)
|
33
|
+
case rgx
|
34
|
+
when Symbol, Regexp
|
35
|
+
syntaxes << ArgumentMatcher.new(rgx, parser, arg_name: as)
|
36
|
+
when Array
|
37
|
+
rgx.each do |rg1|
|
38
|
+
add_syntax( rg1, parser, as: as)
|
34
39
|
end
|
35
40
|
end
|
41
|
+
end
|
36
42
|
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
43
|
+
def define_arg name, &blk
|
44
|
+
SyntaxDefiner.new(self, name).run(blk)
|
45
|
+
end
|
46
|
+
|
47
|
+
def parse argv
|
48
|
+
until argv.empty?
|
49
|
+
argv = _parse_next argv
|
42
50
|
end
|
51
|
+
_check_required_kwds
|
52
|
+
[options, args, errors]
|
53
|
+
end
|
43
54
|
|
44
55
|
|
45
|
-
|
56
|
+
private
|
46
57
|
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
58
|
+
def initialize &blk
|
59
|
+
@args = []
|
60
|
+
@allowed = nil
|
61
|
+
@conversions = {}
|
62
|
+
@defaults = {}
|
63
|
+
@defined_rules = []
|
64
|
+
@errors = []
|
65
|
+
@required = Set.new
|
66
|
+
@syntaxes = []
|
54
67
|
|
55
|
-
|
56
|
-
|
68
|
+
instance_exec(&blk) if blk
|
69
|
+
@options = OpenStruct.new(defaults)
|
70
|
+
end
|
57
71
|
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
else
|
69
|
-
errors << [:syntax_error, name, "#{value} does not match #{conv.first}"]
|
70
|
-
nil
|
71
|
-
end
|
72
|
+
def _convert(value, name:)
|
73
|
+
conv = conversions.fetch(name, nil)
|
74
|
+
case conv
|
75
|
+
when Symbol
|
76
|
+
value.send conv
|
77
|
+
when Proc
|
78
|
+
conv.(value)
|
79
|
+
when Array
|
80
|
+
if (match = conv.first.match(value))
|
81
|
+
conv[1].(*match.captures)
|
72
82
|
else
|
73
|
-
value
|
83
|
+
errors << [:syntax_error, name, "#{value} does not match #{conv.first}"]
|
84
|
+
nil
|
74
85
|
end
|
86
|
+
else
|
87
|
+
value
|
75
88
|
end
|
89
|
+
end
|
76
90
|
|
77
|
-
|
78
|
-
|
91
|
+
def _add_proc_conversion(param, conversion, block, required)
|
92
|
+
Array(param).each do |para|
|
93
|
+
@required.add para if required == :required
|
94
|
+
conversions[para] = block ? [conversion, block] : conversion
|
79
95
|
end
|
96
|
+
end
|
80
97
|
|
81
|
-
|
82
|
-
|
83
|
-
if
|
84
|
-
|
85
|
-
end
|
86
|
-
_parse_symbolic first, rest
|
98
|
+
def _add_symbolic_conversion(param, conversion, required)
|
99
|
+
Array(param).each do |para|
|
100
|
+
@required.add para if required == :required
|
101
|
+
conversions[para] = Predefined.fetch(conversion, conversion)
|
87
102
|
end
|
103
|
+
end
|
88
104
|
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
when %r{(.*):\z}
|
95
|
-
_parse_value $1.gsub('-', '_').to_sym, rest
|
96
|
-
else
|
97
|
-
_parse_syntax(first)
|
98
|
-
rest
|
99
|
-
end
|
105
|
+
def _parse_next argv
|
106
|
+
first, *rest = argv
|
107
|
+
if first == '--'
|
108
|
+
@args += rest
|
109
|
+
return []
|
100
110
|
end
|
111
|
+
_parse_symbolic first, rest
|
112
|
+
end
|
101
113
|
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
114
|
+
def _parse_symbolic first, rest
|
115
|
+
case first
|
116
|
+
when %r{\A:(.*)}
|
117
|
+
switch = $1.gsub('-','_').to_sym
|
118
|
+
_check_switch(switch)
|
119
|
+
options[switch]=true
|
120
|
+
rest
|
121
|
+
when %r{(.*):\z}
|
122
|
+
kwd = $1.gsub('-', '_').to_sym
|
123
|
+
_check_kwd(kwd)
|
124
|
+
_parse_value kwd, rest
|
125
|
+
when %r{\A\\(.*)}
|
126
|
+
args << $1
|
127
|
+
rest
|
128
|
+
else
|
129
|
+
_parse_syntax(first)
|
130
|
+
rest
|
106
131
|
end
|
132
|
+
end
|
107
133
|
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
errors << [:missing_required_value, name]
|
115
|
-
[]
|
134
|
+
def _parse_syntax first
|
135
|
+
value, as = syntaxes.find_value(first){ |matcher| matcher.match(first) }
|
136
|
+
if as
|
137
|
+
options[as] = value
|
138
|
+
else
|
139
|
+
args << value
|
116
140
|
end
|
141
|
+
end
|
117
142
|
|
143
|
+
def _parse_value name, rest
|
144
|
+
value, *rest1 = rest
|
145
|
+
if value
|
146
|
+
options[name] = _convert(value, name: name)
|
147
|
+
return rest1
|
148
|
+
end
|
149
|
+
errors << [:missing_required_value, name]
|
150
|
+
[]
|
118
151
|
end
|
152
|
+
|
119
153
|
end
|
154
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
class Lab42::Rgxargs::ArgumentMatcher
|
2
|
+
require_relative './error'
|
3
|
+
require_relative './predefined_matchers'
|
4
|
+
|
5
|
+
Predefined = Lab42::Rgxargs::PredefinedMatchers
|
6
|
+
Error = Lab42::Rgxargs::Error
|
7
|
+
|
8
|
+
attr_reader :arg_name, :converter, :matcher
|
9
|
+
|
10
|
+
|
11
|
+
|
12
|
+
def match value
|
13
|
+
case matcher
|
14
|
+
when Regexp
|
15
|
+
match = matcher.match(value)
|
16
|
+
match && [converter.(*match.captures), arg_name]
|
17
|
+
else
|
18
|
+
matcher.to_s == value && [converter.(), arg_name]
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
private
|
23
|
+
|
24
|
+
def initialize(matcher, converter, arg_name: nil)
|
25
|
+
@arg_name = arg_name
|
26
|
+
@matcher = matcher
|
27
|
+
@converter = converter || _get_predefined
|
28
|
+
end
|
29
|
+
|
30
|
+
def _get_predefined
|
31
|
+
@matcher, converter = Predefined.fetch(matcher) { raise Error, "undefined syntax #{matcher}" }
|
32
|
+
converter
|
33
|
+
end
|
34
|
+
|
35
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
module Lab42
|
2
|
+
class Rgxargs
|
3
|
+
module Checker
|
4
|
+
|
5
|
+
private
|
6
|
+
|
7
|
+
def _check_kwd(kwd)
|
8
|
+
return if allowed.nil?
|
9
|
+
return if allowed.member? kwd
|
10
|
+
return if required.member? kwd
|
11
|
+
errors << [:unauthorized_kwd, kwd]
|
12
|
+
end
|
13
|
+
|
14
|
+
def _check_required_kwds
|
15
|
+
missing = required - options.to_h.keys
|
16
|
+
@errors += missing.map(&_mk_pair(:required_kwd_missing))
|
17
|
+
end
|
18
|
+
|
19
|
+
|
20
|
+
def _mk_pair(prefix)
|
21
|
+
-> element do
|
22
|
+
[prefix, element]
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
def _check_switch(_)
|
27
|
+
|
28
|
+
end
|
29
|
+
|
30
|
+
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
module Lab42
|
2
|
+
class Rgxargs
|
3
|
+
module Constrainer
|
4
|
+
|
5
|
+
def allow_kwds(*kwds)
|
6
|
+
@allowed = (allowed||Set.new).union(Set.new(kwds.flatten))
|
7
|
+
end
|
8
|
+
|
9
|
+
def require_kwds(*kwds)
|
10
|
+
@required = (required||Set.new).union(Set.new(kwds.flatten))
|
11
|
+
end
|
12
|
+
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
@@ -1,9 +1,10 @@
|
|
1
1
|
module Lab42::Rgxargs::PredefinedMatchers extend self
|
2
2
|
PREDEFINED = {
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
3
|
+
int: [%r{\A([-+]?\d+)\z}, :to_i.to_proc],
|
4
|
+
int_list: [%r{\A(-?\d+(?:,-?\d+)*)\z}, ->(*groups){ groups.first.split(",").map(&:to_i)}],
|
5
|
+
int_range: [%r{\A(-?\d+)(?:-|\.\.)(-?\d+)\z}, ->(f, l){ Range.new(f.to_i, l.to_i) }],
|
6
|
+
list: [%r{(\w+)(?:,(\w+))*}, ->(*groups){ groups.compact }],
|
7
|
+
range: [%r{\A(\d+)\.\.(\d+)\z}, ->(*groups){ Range.new(*groups.map(&:to_i)) }]
|
7
8
|
}
|
8
9
|
|
9
10
|
def defined_names
|
@@ -16,12 +17,11 @@ module Lab42::Rgxargs::PredefinedMatchers extend self
|
|
16
17
|
end
|
17
18
|
|
18
19
|
def list_matcher values
|
19
|
-
[%r{\A((?:#{values.join("|")})(?:,(?:#{values.join("|")}))*)\z}, _list_extractor]
|
20
|
+
[%r{\A((?:#{values.join("|")})(?:,(?:#{values.join("|")}))*)\z}, method(:_list_extractor)]
|
20
21
|
end
|
21
22
|
|
22
23
|
|
23
|
-
|
24
|
-
|
25
|
-
@__list_extractor__ ||= ->(groups){ groups.first.split(",") }
|
24
|
+
def _list_extractor(*groups)
|
25
|
+
groups.first.split(",")
|
26
26
|
end
|
27
27
|
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
class Lab42::Rgxargs::Syntax
|
2
|
+
|
3
|
+
attr_reader :converter, :matcher
|
4
|
+
|
5
|
+
def matches? value
|
6
|
+
if match = matcher.match(value)
|
7
|
+
yield converter.(*match.captures)
|
8
|
+
true
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
private
|
13
|
+
|
14
|
+
def initialize matcher, converter
|
15
|
+
@converter = converter
|
16
|
+
@matcher = matcher
|
17
|
+
end
|
18
|
+
|
19
|
+
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
# Instanciated with an Rgxargs parser it can run a block
|
2
|
+
# in its own context so that the block accesses the
|
3
|
+
# parser's functionality with syntactic sugar w/o cluttering
|
4
|
+
# ther parser itself with too many methods
|
5
|
+
# E.g.:
|
6
|
+
#
|
7
|
+
# ```ruby
|
8
|
+
# syntax
|
9
|
+
#
|
10
|
+
# ```
|
11
|
+
class Lab42::Rgxargs::SyntaxDefiner
|
12
|
+
|
13
|
+
|
14
|
+
attr_reader :arg_name, :parser
|
15
|
+
|
16
|
+
def run code
|
17
|
+
instance_exec(&code)
|
18
|
+
end
|
19
|
+
|
20
|
+
def syntax(matcher, value=nil, &blk)
|
21
|
+
if value
|
22
|
+
parser.add_syntax(matcher, ->(){value}, as: arg_name )
|
23
|
+
else
|
24
|
+
parser.add_syntax(matcher, blk, as: arg_name)
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
private
|
29
|
+
|
30
|
+
def initialize(parser, arg_name)
|
31
|
+
@arg_name = arg_name
|
32
|
+
@parser = parser
|
33
|
+
end
|
34
|
+
end
|
metadata
CHANGED
@@ -1,15 +1,29 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: lab42_rgxargs
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1.
|
4
|
+
version: 0.1.6
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Robert Dober
|
8
|
-
autorequire:
|
8
|
+
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2020-01-
|
11
|
+
date: 2020-01-27 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: speculate_about
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: 0.1.2
|
20
|
+
type: :development
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - "~>"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: 0.1.2
|
13
27
|
- !ruby/object:Gem::Dependency
|
14
28
|
name: rspec
|
15
29
|
requirement: !ruby/object:Gem::Requirement
|
@@ -38,6 +52,20 @@ dependencies:
|
|
38
52
|
- - "~>"
|
39
53
|
- !ruby/object:Gem::Version
|
40
54
|
version: '3.7'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: pry-doc
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - "~>"
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '1.0'
|
62
|
+
type: :development
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - "~>"
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '1.0'
|
41
69
|
description: Parse CL args according to regexen
|
42
70
|
email: robert.dober@gmail.com
|
43
71
|
executables: []
|
@@ -46,12 +74,18 @@ extra_rdoc_files: []
|
|
46
74
|
files:
|
47
75
|
- lib/lab42/enumerable.rb
|
48
76
|
- lib/lab42/rgxargs.rb
|
77
|
+
- lib/lab42/rgxargs/argument_matcher.rb
|
78
|
+
- lib/lab42/rgxargs/checker.rb
|
79
|
+
- lib/lab42/rgxargs/constrainer.rb
|
80
|
+
- lib/lab42/rgxargs/error.rb
|
49
81
|
- lib/lab42/rgxargs/predefined_matchers.rb
|
82
|
+
- lib/lab42/rgxargs/syntax.rb
|
83
|
+
- lib/lab42/rgxargs/syntax_definer.rb
|
50
84
|
homepage: https://github.com/robertdober/lab42_rgxargs
|
51
85
|
licenses:
|
52
86
|
- Apache-2.0
|
53
87
|
metadata: {}
|
54
|
-
post_install_message:
|
88
|
+
post_install_message:
|
55
89
|
rdoc_options: []
|
56
90
|
require_paths:
|
57
91
|
- lib
|
@@ -59,15 +93,15 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
59
93
|
requirements:
|
60
94
|
- - ">="
|
61
95
|
- !ruby/object:Gem::Version
|
62
|
-
version:
|
96
|
+
version: 2.7.0
|
63
97
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
64
98
|
requirements:
|
65
99
|
- - ">="
|
66
100
|
- !ruby/object:Gem::Version
|
67
101
|
version: '0'
|
68
102
|
requirements: []
|
69
|
-
rubygems_version: 3.
|
70
|
-
signing_key:
|
103
|
+
rubygems_version: 3.1.2
|
104
|
+
signing_key:
|
71
105
|
specification_version: 4
|
72
106
|
summary: Parse CL args according to regexen
|
73
107
|
test_files: []
|