argument_parser 0.0.0 → 0.1.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: de34c01a224dda66a54884deaf0818e83855515d33281a8b7191a96e27c8f987
4
- data.tar.gz: 8ae1418b2bdeb6c9fb25b339e3cc70e335d91bc42de9871f1e889c789303d1dc
3
+ metadata.gz: 5422411476cd13036bd0c77fe5d2a7dccdbfda4283c8291b02659277bebd14cd
4
+ data.tar.gz: 7cbc193dea73812eb5c280c842e79e7af3306a1fd8b4215e6d1ad391c2f3ffc2
5
5
  SHA512:
6
- metadata.gz: 7ad9f308dd95fceb6bae98c97d65075312fb0133937fd8367ab37d04188ab061d5ae640926f805433f916468ef88adc287ae810bfaf55937b7a35ed0f0cd1683
7
- data.tar.gz: 6fb21b3496c06b8ab9ce58ee60071e6f703c0edfbbf371b4d50affb0b73bd1f4ffbfb58706e138e29310a88d359d796dd0485639989c5edd3eda7e718cf494ab
6
+ metadata.gz: 903fdc56168e1a8f6e82e37c55f94b1bb1605e1d4e5575d6e62975932e7c454f2e48fda27dc5778d68a2666aa25670578e8ec7cfdfbe51947bccffdf43e9733a
7
+ data.tar.gz: '094e60864b261af857b88cc2bc8687d83325df3a2cc6cbf25804f5ba4984e38ef464033a305f9e35adbdeaa66ca7cf99859840af4d40926db8a5537542718df2'
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module ArgumentParser
4
- VERSION = "0.0.0"
4
+ VERSION = "0.1.1"
5
5
  end
@@ -3,4 +3,125 @@
3
3
  require_relative "argument_parser/version"
4
4
 
5
5
  module ArgumentParser
6
+ extend self
7
+
8
+ Error = Class.new(StandardError)
9
+ SchemaError = Class.new(Error)
10
+ MissingArgument = Class.new(Error)
11
+ InvalidArgument = Class.new(Error)
12
+
13
+ class Parser < Data.define(:schema)
14
+ def parse!(argv = ARGV)
15
+ i = 0
16
+
17
+ args = schema.each_with_object({}) do |rule, result|
18
+ case rule.kind
19
+ in :required
20
+ arg = argv[i]
21
+ raise MissingArgument, "missing required argument: #{rule.name}" if arg.nil?
22
+ arg = validate_pattern!(arg, rule.options)
23
+
24
+ result[rule.name] = arg
25
+ i += 1
26
+ in :optional
27
+ arg = validate_pattern!(argv[i], rule.options)
28
+
29
+ result[rule.name] = arg || rule.options[:default]
30
+ i += 1 if arg
31
+ in :rest
32
+ rest_args = argv.dup[i..] || []
33
+ validate_size(rest_args, rule.options)
34
+ rest_args.map! { |it| validate_pattern!(it, rule.options) }
35
+
36
+ result[rule.name] = rest_args
37
+ i = argv.size
38
+ end
39
+ end
40
+
41
+ argv.shift(i)
42
+
43
+ args
44
+ end
45
+
46
+ private
47
+
48
+ def validate_pattern!(arg, options)
49
+ coerced_arg = coerce!(arg, options)
50
+ return coerced_arg unless options[:pattern]
51
+ return coerced_arg unless arg
52
+ return coerced_arg if options[:pattern] === coerced_arg
53
+
54
+ raise InvalidArgument, "invalid argument: #{arg}"
55
+ end
56
+
57
+ def validate_size(args, options)
58
+ if (min = options[:min])
59
+ raise InvalidArgument, "expected at least #{min} argument(s)" if args.size < min
60
+ end
61
+
62
+ if (max = options[:max])
63
+ raise InvalidArgument, "expected at most #{max} argument(s)" if args.size > max
64
+ end
65
+ end
66
+
67
+ def coerce!(arg, options)
68
+ return arg unless arg
69
+ return arg unless options[:type]
70
+
71
+ if options[:type] == Integer
72
+ Integer(arg)
73
+ elsif options[:type] == Float
74
+ Float(arg)
75
+ elsif options[:type] == String
76
+ arg
77
+ else
78
+ raise SchemaError, "type not supported: #{options[:type]}"
79
+ end
80
+ rescue ArgumentError
81
+ raise InvalidArgument, "invalid argument: #{arg}"
82
+ end
83
+ end
84
+
85
+ module Schema
86
+ class Builder
87
+ def initialize
88
+ @current_stage = Schema::RequiredStage.new([])
89
+ end
90
+
91
+ def required(...) = @current_stage = @current_stage.required(...)
92
+ def optional(...) = @current_stage = @current_stage.optional(...)
93
+ def rest(...) = @current_stage = @current_stage.rest(...)
94
+ def build = @current_stage.build
95
+ end
96
+
97
+ Rule = Data.define(:kind, :name, :options)
98
+
99
+ RequiredStage = Data.define(:schema) do
100
+ def required(name, **opts)
101
+ self.class.new(schema + [Rule.new(:required, name, opts)])
102
+ end
103
+
104
+ def optional(name, **opts)
105
+ OptionalStage.new(schema + [Rule.new(:optional, name, opts)])
106
+ end
107
+
108
+ def rest(name, **opts)
109
+ RestStage.new(schema + [Rule.new(:rest, name, opts)])
110
+ end
111
+
112
+ def build = Parser.new(schema)
113
+ end
114
+
115
+ class OptionalStage < RequiredStage
116
+ def required(*) = raise SchemaError, "cannot add required arguments after optional/rest"
117
+ def optional(*) = raise SchemaError, "only one optional argument is allowed"
118
+ end
119
+
120
+ class RestStage < OptionalStage
121
+ def rest(*) = raise SchemaError, "only one rest argument is allowed"
122
+ end
123
+ end
124
+
125
+ def schema = Schema::RequiredStage.new([])
126
+ def build(&block) = Schema::Builder.new.instance_eval(&block).build
6
127
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: argument_parser
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.0
4
+ version: 0.1.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Matheus Richard
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2025-09-16 00:00:00.000000000 Z
11
+ date: 2025-09-17 00:00:00.000000000 Z
12
12
  dependencies: []
13
13
  description: Parse command line arguments with like you parse options with OptionParser.
14
14
  email: