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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: ad2ab026f6192cc81dd04008d035a79188ed42723b4d687a536a49c010d8a0db
4
- data.tar.gz: b4503cbb9403aec807fb871c5d901690d6ba026edb8c6b6080e0af4506b6e2a7
3
+ metadata.gz: 6c2b779615c5996b97aaa6fbb336adaecaba2119168d9cd6e28665bca4f26587
4
+ data.tar.gz: d1f125fb9a12342f54c3f6748d0a93c3782fc46d0abefd0330324a1ebe3aee3a
5
5
  SHA512:
6
- metadata.gz: e41fc413182c5a6e6ca070c8980b9356738df2b956915c1fdf55849136642ff36b97cef4ee01e1fc3505269a7f9c7b9328044bd8c7a1d4b3401e08aa8820a5b8
7
- data.tar.gz: e75cbfc5b427e68838513444862d0e3ccca90fe5363f517fe24f40beae2655c830c020f2c55559375069bfe837c4ab55940559f3625e318656b12c9c4ff3d5cc
6
+ metadata.gz: dab565b74468cc86dfdedcc162343fc9b85eae244d908a0422b78ef68c5cae65c49e1eb0acf8463bc0a492a645f89441c2f71438e7671eac4534aca89b19bbdf
7
+ data.tar.gz: 7bb8d96d57afeb88a720c6500dcefda5b2f8fc24e877112c0930e6062e0918b5fa304aa3816e757a1885e51567ed24c3cfec238b73d30678d6e99fe7be4b8410
@@ -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
- conversions[param] = Predefined.fetch(conversion, conversion)
26
+ _add_symbolic_conversion(param, conversion, required)
20
27
  else
21
- conversions[param] = conversion
28
+ _add_proc_conversion(param, conversion, block, required)
22
29
  end
23
30
  end
24
31
 
25
- def add_syntax(rgx, parser=nil)
26
- if parser
27
- syntaxes << [rgx, parser]
28
- else
29
- if predef = Predefined.fetch(rgx)
30
- syntaxes << predef
31
- else
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
- def parse argv
38
- until argv.empty?
39
- argv = _parse_next argv
40
- end
41
- [options, args, errors]
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
- private
56
+ private
46
57
 
47
- def initialize &blk
48
- @args = []
49
- @conversions = {}
50
- @defined_rules = []
51
- @errors = []
52
- @options = OpenStruct.new
53
- @syntaxes = []
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
- instance_exec(&blk) if blk
56
- end
68
+ instance_exec(&blk) if blk
69
+ @options = OpenStruct.new(defaults)
70
+ end
57
71
 
58
- def _convert(value, name:)
59
- conv = conversions.fetch(name, nil)
60
- case conv
61
- when Symbol
62
- value.send conv
63
- when Proc
64
- conv.(value)
65
- when Array
66
- if (match = conv.first.match(value))
67
- conv.last.(match.captures)
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
- def _defined_rules(_arg)
78
- false
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
- def _parse_next argv
82
- first, *rest = argv
83
- if _defined_rules(first)
84
- return rest
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
- def _parse_symbolic first, rest
90
- case first
91
- when %r{\A:(.*)}
92
- options[$1.gsub('-','_').to_sym]=true
93
- rest
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
- def _parse_syntax first
103
- args << syntaxes.find_value(first) do |(rgx, converter)|
104
- (match = rgx.match(first)) && converter.(match.captures)
105
- end
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
- def _parse_value name, rest
109
- value, *rest1 = rest
110
- if value
111
- options[name] = _convert(value, name: name)
112
- return rest1
113
- end
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
@@ -0,0 +1,2 @@
1
+ class Lab42::Rgxargs::Error < RuntimeError
2
+ end
@@ -1,9 +1,10 @@
1
1
  module Lab42::Rgxargs::PredefinedMatchers extend self
2
2
  PREDEFINED = {
3
- int_list: [%r{\A(-?\d+(?:,-?\d+)*)\z}, ->(groups){ groups.first.split(",").map(&:to_i)}],
4
- int_range: [%r{\A(-?\d+)(?:-|\.\.)(-?\d+)\z}, ->((f, l)){ Range.new(f.to_i, l.to_i) }],
5
- list: [%r{(\w+)(?:,(\w+))*}, ->(groups){ groups.compact }],
6
- range: [%r{\A(\d+)\.\.(\d+)\z}, ->(groups){ Range.new(*groups.map(&:to_i)) }]
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
- # Memoized
24
- def _list_extractor
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.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-18 00:00:00.000000000 Z
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: '0'
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.0.6
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: []