sprinkles-opts 0.1.0 → 0.2.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: aa12d8ee5410cdbd3e47d4f1b2e1cec293b9097208dbbaae043d7804da3153cf
4
- data.tar.gz: 3ae63c4d2bc388276778ae46809571f4b4e975a90f2618ab7ce73427245fc67b
3
+ metadata.gz: 9e4b137fd5adbc7abaf8dcf83d4129fb99762dd1312373c596be6894814085da
4
+ data.tar.gz: f2980f5b6f3abf8906049759ed1f1edeec7f3986bd57278670b75abb0fe9a2b2
5
5
  SHA512:
6
- metadata.gz: fa177fc8e6752839665457657eff697776e12324dfab2ce47b0f59be0c28729346ec246818a4c135cea07ca7b4aefb6b5da2ccb12ca513c72324751751e37ecf
7
- data.tar.gz: 63963328fb25de91205f032fc86332b1dc25066b5cc8bf2756e8cf7300e4af330eabe17a4448bd69104fa6bbcea6512cae6494139f9090ff20d93c431845c396
6
+ metadata.gz: 37b02710c9b1e6bf6189aeae192e7a805aba61cc0d6518b3fdc60e369cd145f723a22c1510bf53ab7197b322a9ecb48c657102a86deeca426ec254c6c074fa7c
7
+ data.tar.gz: ac3191f10b60d631f2a4e1e2cfafbca62ff87c4e9a9b06e66664fc8253aecf6acf8cafa835c65d75d09031a6baceeb6901292e58c452a804092d7a175dcc3743
@@ -19,18 +19,15 @@ jobs:
19
19
  runs-on: ubuntu-latest
20
20
  strategy:
21
21
  matrix:
22
- ruby-version: ['2.6', '2.7']
22
+ ruby-version: ['3.0', '3.1', '3.2', '3.3', '4.0']
23
23
 
24
24
  steps:
25
- - uses: actions/checkout@v2
25
+ - uses: actions/checkout@v6
26
26
  - name: Set up Ruby
27
- # To automatically get bug fixes and new Ruby versions for ruby/setup-ruby,
28
- # change this to (see https://github.com/ruby/setup-ruby#versioning):
29
- # uses: ruby/setup-ruby@v1
30
- uses: ruby/setup-ruby@473e4d8fe5dd94ee328fdfca9f8c9c7afc9dae5e
27
+ uses: ruby/setup-ruby@v1
31
28
  with:
32
29
  ruby-version: ${{ matrix.ruby-version }}
33
- bundler-cache: true # runs 'bundle install' and caches installed gems automatically
30
+ bundler-cache: true
34
31
  - name: Run tests
35
32
  run: bundle exec rake
36
33
  - name: Typecheck
data/.gitignore CHANGED
@@ -7,3 +7,6 @@
7
7
  /spec/reports/
8
8
  /tmp/
9
9
  *~
10
+ bin/tapioca
11
+ .ruby-version
12
+ Gemfile.lock
data/README.md CHANGED
@@ -5,16 +5,16 @@ argument parsing.
5
5
 
6
6
  ## Basic usage
7
7
 
8
- Create a class that is a subclass of `Spinkles::Opts::GetOpt`. Define fields and their types with `const`, analogously to [how you would with `T::Struct`](), but those fields can have `short:` and `long:` options that map to the flags used to provide them. You'll also have to provide a value for `program_name` by overriding an abstract method:
8
+ Create a class that is a subclass of `Spinkles::Opts::GetOpt`. Define fields and their types with `const`, analogously to [how you would with `T::Struct`](https://sorbet.org/docs/tstruct), but those fields can have `short:` and `long:` options that map to the comman-line options used to provide them. You may also provide a value for `program_name` by overriding an abstract method, which will otherwise default to `$PROGRAM_NAME`:
9
9
 
10
10
  ```ruby
11
11
  class MyOptions < Sprinkles::Opts::GetOpt
12
- sig {override.returns(String)}
13
- def self.program_name; "my-program"; end
12
+ sig { override.returns(String) }
13
+ def self.program_name = "my-program"
14
14
 
15
- const :input, String, short: 'i', long: 'input'
16
- const :num_iterations, Integer, short: 'n', placeholder: 'N'
17
- const :verbose, T::Boolean, short: 'v', long: 'verbose', factory: -> {false}
15
+ const :input, String, short: "i", long: "input"
16
+ const :num_iterations, Integer, short: "n", placeholder: "N"
17
+ const :verbose, T::Boolean, short: "v", long: "verbose", factory: -> { false }
18
18
  end
19
19
  ```
20
20
 
@@ -22,7 +22,7 @@ You can then call `MyOptions.parse(ARGV)` in order to get a value of type `MyOpt
22
22
 
23
23
  ```ruby
24
24
  opts = MyOptions.parse(%w{-i foo -n 8 --verbose})
25
- assert_equal('foo', opts.input)
25
+ assert_equal("foo", opts.input)
26
26
  assert_equal(8, opts.num_iterations)
27
27
  assert_equal(true, opts.verbose)
28
28
  ```
@@ -33,16 +33,13 @@ Fields without a `short:` or `long:` parameter will be understood to be position
33
33
 
34
34
  ```ruby
35
35
  class PosOptions < Sprinkles::Opts::GetOpt
36
- sig {override.returns(String)}
37
- def self.program_name; "positional-options"; end
38
-
39
36
  const :source, String
40
37
  const :destination, String
41
38
  end
42
39
 
43
40
  opts = PosOptions.parse(%w{this that})
44
- assert_equal('this', opts.source)
45
- assert_equal(that, opts.destination)
41
+ assert_equal("'this", opts.source)
42
+ assert_equal("that", opts.destination)
46
43
  ```
47
44
 
48
45
  Parsing will fail and exit the program with a usage statement if either too many or too few positional parameters are provided.
@@ -55,11 +52,13 @@ opts = PosOptions.parse(%w{this})
55
52
  # -h, --help Prints this help
56
53
  ```
57
54
 
55
+ In addition to only providing `const` (and therefore not allowing writer methods for the relevant fields) the resulting objects has been frozen and cannot be mutated at all, even by other methods. The intended use of a `GetOpt` subclass is as a pure data container; any other logic should be implemented as a wrapper around the container.
56
+
58
57
  ## Optional arguments
59
58
 
60
59
  There are two ways of making arguments optional:
61
60
  - A field whose type is marked as `T.nilable` will implicitly be initialized as `nil` if it is not provided.
62
- - A field can have a `factory:` which should be a lambda that will be called to initialize the field if the argument is not provided.
61
+ - A field can have a `factory:` which should be a proc that will be called to initialize the field if the argument is not provided.
63
62
 
64
63
  Fields that are not `T.nilable` and do not have a `factory:` must be provided when parsing arguments.
65
64
 
@@ -67,9 +66,6 @@ For _positional_ arguments, there's currently an extra restriction: all mandator
67
66
 
68
67
  ```ruby
69
68
  class PosOptions < Sprinkles::Opts::GetOpt
70
- sig {override.returns(String)}
71
- def self.program_name; "positional-options"; end
72
-
73
69
  const :a, String
74
70
  const :b, T.nilable(String)
75
71
  const :c, T.nilable(String)
@@ -117,6 +113,33 @@ PosArray.parse(%w{-a 5}) # a is [5]
117
113
  PosArray.parse(%w{-a 22 -a 33}) # a is [22, 33]
118
114
  ```
119
115
 
116
+ ## Other data types
117
+
118
+ Not all types are valid, and invalid types will cause a load-time exception. Basic Ruby types including `String`, `Symbol`, `Integer`, and `Float` are all valid field types, as well as a few gem-provided types like `Date` and `URI`. You can also provide a Sorbet `T::Enum` type and it will deserialize it from the provided value if possible.
119
+
120
+ Additionally, you can use a `T.any` of multiple types, and arguments will use successive attempts at parsing, falling back on the later types if the provided string cannot be parsed as an earlier type. One note is that it will attempt parsing in the order of the `T.any`, but some types will always parse correctly: for example, if you have a field whose type is `T.any(String, URI)`, then the field will never actually be set to a `URI` because it's impossible to provide an invalid `String` value.
121
+
122
+ ```ruby
123
+ class TrafficLight < T::Enum
124
+ enums do
125
+ Green = new("green")
126
+ Yellow = new("yellow")
127
+ Red = new("red")
128
+ end
129
+ end
130
+
131
+ class OtherValues < Sprinkles::Opts::GetOpt
132
+ const :num, Integer, short: "n"
133
+ const :date, Date, short: "d"
134
+ const :tl, TrafficLight, short: "t"
135
+ end
136
+
137
+ OtherValues.parse(%w{-d 2015-07-01 -n 33 -t yellow})
138
+ # num is 22
139
+ # date is Date.new(2015, 07, 01)
140
+ # tl is TrafficLight::Yellow
141
+ ```
142
+
120
143
  ## Help text and descriptions
121
144
 
122
145
  The option names `-h` and `--help` are reserved, and when they are provided the program will print a usage panel and exit:
@@ -131,7 +154,6 @@ Usage: my-program --input=VALUE -nN
131
154
 
132
155
  Individual fields can customize their default placeholder text away from the default `VALUE` using the `placeholder:` argument, and can provide more extensive descriptions using the `description:` argument.
133
156
 
134
-
135
157
  ## Why sprinkles?
136
158
 
137
159
  Well, because it's a Sorbet topping. I have other unfinished ideas for how to leverage Sorbet to write certain abstractions, and my thought was that it might be nice to put them in a common namespace.
data/Rakefile CHANGED
@@ -1,10 +1,10 @@
1
- require 'bundler/gem_tasks'
2
- require 'rake/testtask'
1
+ require "bundler/gem_tasks"
2
+ require "rake/testtask"
3
3
 
4
4
  Rake::TestTask.new(:test) do |t|
5
- t.libs << 'test'
6
- t.libs << 'lib'
7
- t.test_files = FileList['test/**/*_test.rb']
5
+ t.libs << "test"
6
+ t.libs << "lib"
7
+ t.test_files = FileList["test/**/*_test.rb"]
8
8
  end
9
9
 
10
- task default: :test
10
+ task(default: :test)
@@ -3,6 +3,6 @@
3
3
 
4
4
  module Sprinkles
5
5
  module Opts
6
- VERSION = '0.1.0'
6
+ VERSION = "0.2.0"
7
7
  end
8
8
  end