[#120465] [Ruby master Bug#20998] rb_str_locktmp() changes flags of frozen strings and string literals — "Eregon (Benoit Daloze) via ruby-core" <ruby-core@...>

Issue #20998 has been reported by Eregon (Benoit Daloze).

17 messages 2025/01/03

[#120469] [Ruby master Feature#21000] A way to avoid loading constant required by a type check — "Dan0042 (Daniel DeLorme) via ruby-core" <ruby-core@...>

Issue #21000 has been reported by Dan0042 (Daniel DeLorme).

13 messages 2025/01/03

[#120488] [Ruby master Feature#21005] Update the source location method to include line start/stop and column start/stop details — "bkuhlmann (Brooke Kuhlmann) via ruby-core" <ruby-core@...>

SXNzdWUgIzIxMDA1IGhhcyBiZWVuIHJlcG9ydGVkIGJ5IGJrdWhsbWFubiAoQnJvb2tlIEt1aGxt

16 messages 2025/01/05

[#120580] [Ruby master Bug#21021] "try to mark T_NONE object" with 3.4.1 — "Benoit_Tigeot (Benoit Tigeot) via ruby-core" <ruby-core@...>

SXNzdWUgIzIxMDIxIGhhcyBiZWVuIHJlcG9ydGVkIGJ5IEJlbm9pdF9UaWdlb3QgKEJlbm9pdCBU

28 messages 2025/01/09

[#120601] [Ruby master Bug#21024] Ruby including <cstdbool> generates compilation warning with GCC 15, header is deprecated in C++17, — "jprokop (Jarek Prokop) via ruby-core" <ruby-core@...>

Issue #21024 has been reported by jprokop (Jarek Prokop).

7 messages 2025/01/10

[#120617] [Ruby master Feature#21028] Method for finding why an object isn't Ractor shareable — "tenderlovemaking (Aaron Patterson) via ruby-core" <ruby-core@...>

Issue #21028 has been reported by tenderlovemaking (Aaron Patterson).

7 messages 2025/01/11

[#120618] [Ruby master Bug#21029] Prism behavior for `defined? (;x)` differs — "qnighy (Masaki Hara) via ruby-core" <ruby-core@...>

Issue #21029 has been reported by qnighy (Masaki Hara).

12 messages 2025/01/12

[#120619] [Ruby master Bug#21030] Bug: #step with Range<ActiveSupport::Duration> behavior broken on Ruby 3.4.1 — "johnnyshields (Johnny Shields) via ruby-core" <ruby-core@...>

Issue #21030 has been reported by johnnyshields (Johnny Shields).

11 messages 2025/01/12

[#120628] [Ruby master Bug#21031] Incompatibility with prism and parse.y when eval'ing unnamed forwarding variables — "ksss (Yuki Kurihara) via ruby-core" <ruby-core@...>

Issue #21031 has been reported by ksss (Yuki Kurihara).

8 messages 2025/01/13

[#120637] [Ruby master Bug#21032] `Module#autoload?` is slow when `$LOAD_PATH` contains a relative path — "byroot (Jean Boussier) via ruby-core" <ruby-core@...>

Issue #21032 has been reported by byroot (Jean Boussier).

9 messages 2025/01/13

[#120643] [Ruby master Feature#21033] Allow lambdas that don't access `self` to be Ractor shareable — "tenderlovemaking (Aaron Patterson) via ruby-core" <ruby-core@...>

Issue #21033 has been reported by tenderlovemaking (Aaron Patterson).

18 messages 2025/01/13

[#120650] [Ruby master Bug#21034] try to mark T_NONE object error after upgrading to 3.4.1 — "travisbell (Travis Bell) via ruby-core" <ruby-core@...>

Issue #21034 has been reported by travisbell (Travis Bell).

17 messages 2025/01/14

[#120657] [Ruby master Misc#21035] Clarify or redefine Module#autoload? and Module#const_defined? — "fxn (Xavier Noria) via ruby-core" <ruby-core@...>

Issue #21035 has been reported by fxn (Xavier Noria).

28 messages 2025/01/14

[#120694] [Ruby master Bug#21039] Ractor.make_shareable breaks block semantics (seeing updated captured variables) of existing blocks — "Eregon (Benoit Daloze) via ruby-core" <ruby-core@...>

Issue #21039 has been reported by Eregon (Benoit Daloze).

26 messages 2025/01/15

[#120738] [Ruby master Bug#21048] [Prism] rescue in modifier form with condition behaves differently — "Earlopain (Earlopain _) via ruby-core" <ruby-core@...>

Issue #21048 has been reported by Earlopain (Earlopain _).

7 messages 2025/01/19

[#120774] [Ruby master Bug#21087] "try to mark T_NONE object" error in ActiveRecord with 3.4.1 upgrade — "p8 (Petrik de Heus) via ruby-core" <ruby-core@...>

SXNzdWUgIzIxMDg3IGhhcyBiZWVuIHJlcG9ydGVkIGJ5IHA4IChQZXRyaWsgZGUgSGV1cykuDQoN

6 messages 2025/01/23

[#120787] [Ruby master Bug#21088] TCPSocket.new raises Socket::ResolutionError instead of Errno::ECONNREFUSED for hosts defined in /etc/hosts — "dmlary (David Lary) via ruby-core" <ruby-core@...>

Issue #21088 has been reported by dmlary (David Lary).

9 messages 2025/01/24

[#120811] [Ruby master Bug#21095] Prefer `uname -n` over `hostname` in tests. — "ioquatix (Samuel Williams) via ruby-core" <ruby-core@...>

Issue #21095 has been reported by ioquatix (Samuel Williams).

10 messages 2025/01/28

[#120819] [Ruby master Bug#21097] `x = a rescue b in c` and `def f = a rescue b in c` parsed differently between parse.y and prism — "tompng (tomoya ishida) via ruby-core" <ruby-core@...>

Issue #21097 has been reported by tompng (tomoya ishida).

12 messages 2025/01/29

[#120840] [Ruby master Misc#21100] DevMeeting before or after RubyKaigi2025 — "ko1 (Koichi Sasada) via ruby-core" <ruby-core@...>

SXNzdWUgIzIxMTAwIGhhcyBiZWVuIHJlcG9ydGVkIGJ5IGtvMSAoS29pY2hpIFNhc2FkYSkuDQoN

9 messages 2025/01/30

[ruby-core:120606] [Ruby master Feature#21015] Add in a `-g` flag, like `-s` but with a few more quality of life features

From: "sampersand2 (Sam Westerman) via ruby-core" <ruby-core@...>
Date: 2025-01-11 00:26:41 UTC
List: ruby-core #120606
Issue #21015 has been updated by sampersand2 (Sam Westerman).


matz (Yukihiro Matsumoto) wrote in #note-9:
> I like the basic idea of this proposal. But, I am against:
> 
> * `-g` option name. `-s` is relatively unpopular. Even with the proposed improvement, this is kinda old-fashioned way to parse command-line options. I don't want to consume precious single character option here.
> * Adding up the multiple options. If you want more precise interpretation of the command line options, use `optparse` or something similar.
> * Interpreting option values. Conversion should be done by the application, even for the basic values like `nil`, `true`, `false` and integers.
> 
> Matz.


> * Adding up the multiple options. If you want more precise interpretation of the command line options, use `optparse` or something similar.
Totally agree with this. It's a bit awkward, and I think removing it is a good idea. 100% on-board.

> * Interpreting option values. Conversion should be done by the application, even for the basic values like `nil`, `true`, `false` and integers.
While a bit less of a fan of this, I'm ok dropping this, because it's not a huge burden for applications to do `$foo == 'true'`.

> * `-g` option name. `-s` is relatively unpopular. Even with the proposed improvement, this is kinda old-fashioned way to parse command-line options. I don't want to consume precious single character option here.

Few things here:
1. I'd argue the _reason_ `-s` is relatively unpopular is because it's cumbersome and awkward to use---IMO, if it supported `-abc == -a -b -c` from the outset, I think it'd see a lot more use.
2. While this is a somewhat old-fashioned way to parse arguments, I think that it's quite useful when writing shorter scripts. Compare the following, for example:
```ruby
#!ruby -G
while line = gets
	$stdout.flush if $f
	line.chomp! if $l
	print line.dump.slice!(1..-2).gsub(/\\([#'"'])/, '\1')
	puts if $l
end
puts unless $l || $n
```
and
```ruby
#!ruby
require 'optparse'
OptionParser.new do |op|
 op.on '-n' do $n = true end
 op.on '-l' do $l = true end
 op.on '-f' do $f = true end
 op.parse!
end

while line = gets
	$stdout.flush if $f
	line.chomp! if $l
	print line.dump.slice!(1..-2).gsub(/\\([#'"'])/, '\1')
	puts if $l
end
puts unless $l || $n
```
The fact that the option parsing in the second `OptionParser` example is just as long as the entire program in the `-G` example is quite cumbersome. I think there's definitely a niche for "small scripts which just need to support parsing a handful of flags"

3. If `-g` is considered precious, would `-G` or `--switches` be acceptable alternatives? We currently have 28 unused flags (`bfgjkmoqtuzABDGHJLMNOPQRTVYZ`), and of the 26 currently supported flags (`0CEFIKSUWXacdeghilnprsvwxy`), 55% of them are still shared with ruby 0.49 (`FIXacdeilnpsvxy`). I'd argue adding a single extra short or long flag to support this use-case would be reasonable.

I've also considered adding a singleton method on `$*`/`ARGV` (just like how `$LOAD_PATH` has `resolve_feature_path`, however using this would need to be done in `BEGIN` blocks for scripts using `-n`/`-p).


----------------------------------------
Feature #21015: Add in a `-g` flag, like `-s` but with a few more quality of life features
https://bugs.ruby-lang.org/issues/21015#change-111436

* Author: sampersand2 (Sam Westerman)
* Status: Open
----------------------------------------
Add in a `-g` flag, like `-s` but with a few more QOL features

## TL;DR
([PR](https://github.com/ruby/ruby/pull/12526).)

Ruby's `-s` flag has quite a few shortfalls that make it difficult to use when writing scripts . A new `-g` flag will fix it:

```shell
# Support `-abc` as a shorthand for `-a -b -c`
ruby -ge'p [$a, $b, $c]' -- -abc #=> [1, 1, 1]
# ^ (see "How short-form options (`-abc`) are handled" for why it's `1` and not `true`)

# Support `-vvv` as a shorthand for `-v=3`
ruby -ge'p $v' -- -vvv #=> 3

# Support things other than strings:
ruby -ge'p [$n, $f]' -- -n90 -f=false #=> [90, false]

# long-forms don't have a leading `_`
ruby -ge'p $foo_bar' -- --foo-bar #=> true
```

# Background: What is `-s`
Ruby's `-s` flag is an extremely helpful feature when writing short little scripts to set config options; it automatically processes `ARGV` and removes leading "flags" for you, assigning them to global variables.
```ruby
#!/bin/ruby -s

# echo, ruby-style! If `-n` is given, no newline is printed
print ARGV.join(' '), ($n ? "" : "\n")
```

While `-s` is significantly less powerful than `OptionParse`, or even via just parsing options yourselves, it's **incredibly** useful when writing simple little scripts where the option parsing code would be longer than the script itself.

## Problem 1 (The big one): No support for chained short-form flags
The biggest problem with `-s` is that it doesn't let you concatenate short-form flags together: conventionally, `./myprogram -x -y -z` should be the same as `./myprogram -xyz`. However, if `./myprogram` were a ruby program using `-s`, you'd end up with the global variable `$xyz`.

Short scripts that use `-s` to parse options thus need to add the following code to handle all different permutations of `-x`, `-y`, and `-z`:
```ruby
# Handle all permutations of `-xyz`
$xyz || $xzy || $yxz || $yzx || $zxy || $zyx and $x=$y=$z=true

# Handle only two options given
$xy || $yx and $x=$y=true
$xz || $zx and $x=$z=true
$yz || $zy and $y=$z=true

```
Four flags becomes even worse:
```ruby
$wxyz || $wxzy || $wyxz || $wyzx || \
    $wzxy || $wzyx || $xwyz || $xwzy || \
    $xywz || $xyzw || $xzwy || $xzyw || \
    $ywxz || $ywzx || $yxwz || $yxzw || \
    $yzwx || $yzxw || $zwxy || $zwyx || \
    $zxwy || $zxyw || $zywx || $zyxw and $w=$x=$y=$z=true

$wxy || $wyx || $xwy || $xyw || $ywx || $yxw and $w=$x=$y=true
$wxz || $wzx || $xwz || $xzw || $zwx || $zxw and $w=$x=$z=true
$wyz || $wzy || $ywz || $yzw || $zwy || $zyw and $w=$y=$z=true
$xyz || $xzy || $yxz || $yzx || $zxy || $zyx and $x=$y=$z=true

$wx || $xw and $w=$x=true
$wy || $yw and $w=$y=true
$wz || $zw and $w=$z=true
$xy || $yx and $x=$y=true
$xz || $zx and $x=$z=true
$yz || $zy and $y=$z=true
```

This is a huge problem for simple little scripts, as they're forced into an uncomfortable choice:
1. Use `OptionParser`, which is very much overkill for tiny scripts
2. Break from unix standards and require passing short-forms individually (i.e. `./program.rb -x -y -z`)
3. Do the cumbersome permutation checks as shown above
4. Give up on flags all together and use environment variables.

None of these options are great, *especially* because Ruby's all about programmer happiness and none of these options spark joy.

## Problem 2: All values are `Strings`
Less important than the short-form issue is that all values provided to flags become Strings (e.g. `ruby -se'p $foo' -- -foo=30` yields `"30"`). While this can be solved by `$foo = $foo&.to_i` somewhere early on, it's verbose:
```ruby
#!ruby -s

# Very simple benchmarking program
$log_level = $log_level&.to_i
$amount = $amount&.to_i
$timeout = $timeout&.to_i
$precision = $precision&.to_i

$amount.times do |iter|
  start = Time.now

  $log_level > 1 and puts "[iteration: #{iter}] running: #{ARGV}"
  pipe = IO.popen ARGV

  unless select [pipe], nil, nil, $timeout
    warn "took too long!"
    next
  end

  printf "%0.#{$precision}f", Time.now - start
end
```

Moreover, there's no way to create a falsey flag other than just omitting it, which can make interacting with `-s` scripts somewhat irritating:
```ruby
# Have to use `*[... ? ... : nil].compact`, otherwise
# we'd end up passing an empty string/nil as an arg
system("./myprogram.rb", *[enable_foo ? "--foo" : nil].compact)
```
A better solution would be to allow for `--foo=false` or `--foo=true`, and then parse the `false`/`true`.

## Problem 3 (Minor): Long-form options have a leading `_`
Long-form options, such as `--help`, have a leading `_` appended to them (to disambiguate them from `-help`). While it can be worked around (either `alias $help $_help` or just using `$_help` directly), it's irritating enough that I've been known to just force end-users to use `-help`. This diverges from the common "long-form options should have two dashes in front of them," further making ruby scripts with `-s` a bit awkward to use

## Problem 4 (Minor): Repeated flags aren't supported
Sometimes it's useful to know how many times a flag was repeated, such as `-vvv` to enable "very very verbose mode": Using `-s` you must do
```ruby
is_verbose = $v ? 1 : ($vv ? 2 : ($vvv ? 3 : ($vvvv ? 4 : ...)))
```
While I've yet to see a use-case for repeating a flag beyond three or four times, having to manually enumerate everything out is, again, a bit of a pain.





# Solution: Add a new `-g` flag, which supports all this
I propose the addition of a new command-line flag, `-g`, which adds in a new form of argument parsing that solves all these issues. [PR](https://github.com/ruby/ruby/pull/12526)

## Overview:
```shell
ruby -ge'p [$a, $b, $c]'    -- -abc                 #=> [1, 1, 1]
ruby -ge'p $d'              -- -d90                 #=> 90
ruby -ge'p [$d, $e]'        -- -d90e=foo            #=> [90, "foo"]
ruby -ge'p [$hi, $foo_bar]' -- --hi --foo-bar=false #=> [true, false]
ruby -ge'p $x'              -- -xxx                 #=> 3

# Putting it together now, lol.
ruby -g -e'p [$a, $b, $c, $d, $e, $world]' -- -abbcd90e=hello --world=false
# => [true, 2, true, 90, "hello", false]```
```

## Specifics:
After all ruby arguments are parsed, just like `-s`, "switch parsing" is enabled. Just like `-s`, switches are read until `--` or a non-switch (ie doesn't start with `-`) is encountered. The key differences from `-s` are _how_ the switches are handled.

### How short-form options (`-abc`) are handled:
The entire point of this feature, short-form options are handled in a more posix-like style: each character (ASCII-only, akin to `-s`) is parsed as a switch of just one character long. So `-abc` is handled the same exact way as `-a -b -c`. This allows for chaining short-form options together when calling ruby scripts in a convenient and natural way.

There's a few caveats: First, if an `=` is encountered, the last-most character gets that value. So `-abc=foo` is the same as `-a -b -c=foo`. (This is akin to most command-line options, eg ruby's `ruby -aine...`, the `e` gets the `...`.)

Secondly, because numbers aren't valid global variables (`$1`..`$9` are used for regex groups), I think repurposing them to have an implicit `=` beforehand is beneficial. So you can do `-n90` and it'd be the same as `-n=90`. It even supports signs, so `-n+39` is `-n=+39`. (In fact, the implementation I have right now supports `-a123b` as `-a=123 -b`, which I'm a fan of.)


Lastly, to support `-vvv` implying "`$v = 3`", repeating a character sets that variable to the repetition count. A consequence of this is that for `-x`, `-g` will set `$x` to `1` (unlike `-s` which sets `$x` to `true`). This is convenient, as otherwise `puts "log!" if $v > 1` wouldn't really work well. And, since they're both truthy, I think it's ok. However, I could be swayed to just drop this entirely.

### How long-form options (`--foo`) are handled:
Unlike short-form options, long-form ones are handled much more closely to how `-s` handles them, with one key difference: The leading `_` is dropped. (In `-s`, all `-` other than the very first is converted to a `_`, so `--foo` is `$_foo`, and `---bar` is `$__bar`.) I feel like it's much more natural to have `--long-form` be equivalent to the global variable `$long_form`, especially when `-x` is equivalent to `$x`.

(Note: Unlike `-x`, `--foo` will set `$foo` to `true`, not `1`.)

### Parsing after `=`s
The `-s` flag allows supplying values to switches, such as `-foo=abc` will set `$foo` to `"abc"`. However, this is a bit annoying when you want to use integers (or booleans) as the values, as you have to manually check yourself.

So, when `-g` encounters a switch with a `=`, if the value is exactly `true`, `false`, or `nil`, it'll use that value (so `--foo=false` sets `$foo` to `false`, or `-x=nil` sets `$x` to `nil`). Otherwise, it'll attempt to parse the value as an integer, using standard ruby integer parsing rules (i.e. allows signs, underscores, and prefixes like `0x`). This allows users to pass in `--count=30` and then use `($count || 10)` in their code, and not have to do any conversions.

While this implicit conversion usually'd not be great, I think it actually fits quite well: The whole point of `-s` (and `-g`) are for short scripts, which presumably aren't doing a large amount or robust error handling. If error handling's needed, then `-g`'s not the right tool and `OptionParser` or something else should be used. (And, if you need a string always, you can just `$count = $count&.to_s` and get it anyways.)

# Alternatives
(TODO)
1. Do nothing
2. Continue using `-s`
3. Create some function in the runtime, or on `$*`/`ARGV`, that does parsing

# Prior art
Ruby's `-s` is based off of perl's `-s`, which functions (as far as I can tell) identically to Ruby's. I Don't know of any other language that does `-s`, much less `-g`.

# Open Questions
## How should supplying both `-g` and `-s` work?
This is the first flag that'd directly conflict with another command-line flag, so what should be done when both `-g` and `-s` are given (such as `ruby -gs -e'p $x' -- -x=9`). Here's the options as I see them:
1. Use to last supplied flag (in the example `-s`). This'd act like how incompatible flags work in other utilities
2. Always use `-g`, as it can be considered a sort-of a "super set" of `-s`.
3. Emit a warning, and then do either `1.` or `2.`
4. Emit an error, and then do either `1.` or `2.`

I'm personally partial to emitting a warning on `-W2`, and then using the last supplied flag, however I could be convinced to any of the options

## What values after `=` should be parsed?
Currently, if the values are exactly `true`, `false`, `nil` it uses those literals; otherwise, it attempts to parse an int, and if that fails, uses a string.

Should additional types be supported, such as Floats, Symbols, or Pathname? I personally think no, as anything that complicated can be handled by `$x and $x = Float $x` or just `OptionParser`

## Should `-x` do `$x = true` or `$x = 1`
I personally'd like `-x` to be `true`, just like `-s`. However, this conflicts with `-xx` yielding `2`, as `log if $x > 1` wouldn't work. Since `1` is truthy, I've defaulted `-x` to `1`, but I could be convinced to remove it (and even remove the entire `-xx` thing if there was a good argument.)

## Why introduce a new flag? Why name it `-g`?
I think adding in a new flag makes sense: `-g` is a modification of `-s`, so it naturally should be a new flag. (Attempting to shoehorn these options into `-s` would be a nightmare.)

I briefly considered using `-ss` as the flag name, to make it clear that it was a modification of `-s`, however that'd be the first two-character short flag and I didn't want to introduce that. (And, it'd be pretty ironic as a large portion of the impetus behind `-g` is to parse short flags, which `-ss` isn't :-P.)

As for `-g` specifically, I considered `-o` for "options" (nixed because most utilities use it for "output," and I didn't want the cognitive overload), and `-f` for "flags" (nixed because some utilities use it to mean "file," and ruby might use it in the future.) I picked `-g` because it's short for "globals" or "getflags".

# Conclusion
Ruby's all about programmer happiness, and making writing programs easier. Currently, `-s` provides a very rudimentary argument parser, and a slightly more sophisticated one is sorely needed.





-- 
https://bugs.ruby-lang.org/
 ______________________________________________
 ruby-core mailing list -- ruby-core@ml.ruby-lang.org
 To unsubscribe send an email to ruby-core-leave@ml.ruby-lang.org
 ruby-core info -- https://ml.ruby-lang.org/mailman3/lists/ruby-core.ml.ruby-lang.org/


In This Thread

Prev Next