Project

General

Profile

Actions

Feature #20882

open

Provide Boolean(...)

Added by getajobmike (Mike Perham) 10 days ago. Updated 7 days ago.

Status:
Open
Assignee:
-
Target version:
-
[ruby-core:119852]

Description

Ruby provides Integer(...) and Float(...) global methods to coerce values. Is there a similar method for Booleans?

I'd like to do something like:

# ENV["SOME_FEATURE"] is unset
Boolean(ENV["SOME_FEATURE"]) # => false

# ENV["SOME_FEATURE"] is unset, but allow a default?
Boolean(ENV["SOME_FEATURE"], true) # => true

# explicitly disable
ENV["SOME_FEATURE"] = "0"
Boolean(ENV["SOME_FEATURE"], true) # => false

# explicitly enable
ENV["SOME_FEATURE"] = "1"
Boolean(ENV["SOME_FEATURE"]) # => true

Related issues 6 (0 open6 closed)

Related to Ruby master - Feature #20756: Introduce Boolean classRejectedActions
Related to Ruby master - Feature #14224: Boolean classRejectedActions
Related to Ruby master - Feature #13260: Kernel#BooleanRejectedActions
Related to Ruby master - Feature #17265: Add `Bool` moduleFeedbackmatz (Yukihiro Matsumoto)Actions
Related to Ruby master - Bug #12827: Add Boolean data type.RejectedActions
Related to Ruby master - Feature #12515: Create "Boolean" superclass of TrueClass / FalseClassRejectedActions

Updated by ioquatix (Samuel Williams) 10 days ago

I am the current maintainer of the boolean gem. You can check the implementation here: https://github.com/ioquatix/boolean

I think Boolean can be adopted as a core Ruby class, but I think it has been discussed before and rejected because it only has two values. However, for type annotation and type coercion, it can be useful.

Updated by bkuhlmann (Brooke Kuhlmann) 10 days ago

In case it's of interest, I use my Refinements gem for this. Example:

using Refinements::String

ENV["SOME_FEATURE"].to_bool             # Either `true` or `false` depending on the resolved value.
ENV.fetch("SOME_FEATURE", "0").to_bool  # `false`

Updated by HarlemSquirrel (Kevin McCormack) 10 days ago · Edited

A project I work on has added the following patch. I kind of like the simplicity of #to_b

class Object
  # Returns true for '1', 'true', true
  # Returns false for '0', 'false', false, '', nil
  #
  # @return [Boolean]
  def to_boolean
    present? && ActiveRecord::Type::Boolean.new.cast(self)
  end
  alias to_b to_boolean
end

Updated by murb (Maarten Brouwers) 9 days ago

+1 for the request, I don't like to resorting to ActiveRecord::Type::Boolean.new.cast(value) to cast booleans. I would prefer a more explicit .parse which DateTime has though:

DateTime.parse("2021-04-13T14:20")
Boolean.parse("0") # false
Boolean.parse(1) # true
Boolean.parse("t") # true

Updated by Earlopain (Earlopain _) 9 days ago

I'm positive and would like to use something like this as well. However, since ActiveRecord::Type::Boolean from Rails has come up, which values should be considered true?

There are quite a few possible combinations:

  • 0 and 1
  • "0" and "1"
  • "true" and "false"
  • "t" and "f"
  • various other boolean-like words, like "yes"/"no", "on"/"off"
  • symbols
  • a variety of different capitalizations of these

For reference, here is the list that rails currently considers "false": https://github.com/rails/rails/blob/852d0cd4123463cf215f4b024801b256857295c4/activemodel/lib/active_model/type/boolean.rb#L15-L25

Updated by austin (Austin Ziegler) 8 days ago

bunnrf (RF Bunn) wrote in #note-6:

This was rejected 2 months ago
https://bugs.ruby-lang.org/issues/20756

Previously
https://bugs.ruby-lang.org/issues/13260

This is not about a Boolean type, but a Boolean coercion function, Kernel#Boolean or a casting function, Object#to_bool.

I support the concept of a coercion function, but think that if string coercion is down, only case-insensitive true/false values should be supported and possibly 0/1 values. Under no circumstances should we make the NOrway mistake that YAML before 1.2 did. (I believe YAML 1.2 supports True, False, TRUE, FALSE, true, and false only.)

This would be a good set, IMO. I don’t believe that the Rails / ActiveSupport approach is correct (although supporting symbol versions of the strings would be ok).

Updated by Dan0042 (Daniel DeLorme) 7 days ago

Earlopain (A S) wrote in #note-5:

There are quite a few possible combinations:

  • 0 and 1
  • "0" and "1"
  • "true" and "false"
  • "t" and "f"
  • various other boolean-like words, like "yes"/"no", "on"/"off"

I would agree with any of these combinations, but not all of them at once.
For example

puts "answer: yes or no?"
p Boolean(gets.chomp)

This will print "true" even if the answer is "t" rather than "yes", or if the user typo'ed "no" as "on". It seems to me pretty much every variation of this will need to distinguish between 2 values only, and accepting any of 12 preset values will lead to confused logic. "Be liberal in what you accept" but this seems a bit too liberal.

Updated by austin (Austin Ziegler) 7 days ago

Dan0042 (Daniel DeLorme) wrote in #note-8:

I would agree with any of these combinations, but not all of them at once.
For example

puts "answer: yes or no?"
p Boolean(gets.chomp)

This will print "true" even if the answer is "t" rather than "yes", or if the user typo'ed "no" as "on". It seems to me pretty much every variation of this will need to distinguish between 2 values only, and accepting any of 12 preset values will lead to confused logic. "Be liberal in what you accept" but this seems a bit too liberal.

GitHub Actions takes what I think is the right choice for this:

/**
 * Gets the input value of the boolean type in the YAML 1.2 "core schema" specification.
 * Support boolean input list: `true | True | TRUE | false | False | FALSE` .
 * The return value is also in boolean type.
 * ref: https://yaml.org/spec/1.2/spec.html#id2804923
 *
 * @param     name     name of the input to get
 * @param     options  optional. See InputOptions.
 * @returns   boolean
 */
export function getBooleanInput(name: string, options?: InputOptions): boolean {
  const trueValue = ['true', 'True', 'TRUE']
  const falseValue = ['false', 'False', 'FALSE']
  const val = getInput(name, options)
  if (trueValue.includes(val)) return true
  if (falseValue.includes(val)) return false
  throw new TypeError(
    `Input does not meet YAML 1.2 "Core Schema" specification: ${name}\n` +
      `Support boolean input list: \`true | True | TRUE | false | False | FALSE\``
  )
}

In the main cases where this is needed, one is pulling from an environment variable (which is always a string) or similar input. Kernel#Integer throws an exception if the value does not match the expectation of an integer (it is fairly liberal with what makes an integer, accepting decimal, binary, hex, and octal inputs). There is no reason that an equivalent Kernel#Boolean could not do the same and do so with exactly the six values listed above, possibly twelve if we wanted to accept symbol versions as well. I would argue that any other interpretation of a "boolean string" should be handled explicitly by calling #== or #=== (via case) or with pattern matching because otherwise you are opening yourself to invalid or unexpected inputs, which are ultimately security risks.

Updated by duerst (Martin Dürst) 7 days ago

Earlopain (A S) wrote in #note-5:

I'm positive and would like to use something like this as well. However, since ActiveRecord::Type::Boolean from Rails has come up, which values should be considered true?

There are quite a few possible combinations:

  • 0 and 1
  • "0" and "1"
  • "true" and "false"
  • "t" and "f"
  • various other boolean-like words, like "yes"/"no", "on"/"off"
  • symbols
  • a variety of different capitalizations of these

For reference, here is the list that rails currently considers "false": https://github.com/rails/rails/blob/852d0cd4123463cf215f4b024801b256857295c4/activemodel/lib/active_model/type/boolean.rb#L15-L25

I think we shouldn't mix program-internal conversions and human-language choices.

Anything like the following (very rough/quick translations) will not work:

puts "Antwort: Ja oder nein?" # German
p Boolean(gets.chomp)

puts "Reponse: Si ou non?" # French
p Boolean(gets.chomp)

puts "解答: はいまたはいいえ?" # Japanese
p Boolean(gets.chomp)
Actions #11

Updated by hsbt (Hiroshi SHIBATA) 6 days ago

Actions #12

Updated by hsbt (Hiroshi SHIBATA) 6 days ago

Actions #13

Updated by hsbt (Hiroshi SHIBATA) 6 days ago

Actions #14

Updated by hsbt (Hiroshi SHIBATA) 6 days ago

Actions #15

Updated by hsbt (Hiroshi SHIBATA) 6 days ago

  • Related to Bug #12827: Add Boolean data type. added
Actions #16

Updated by hsbt (Hiroshi SHIBATA) 6 days ago

  • Related to Feature #12515: Create "Boolean" superclass of TrueClass / FalseClass added
Actions

Also available in: Atom PDF

Like6
Like0Like0Like0Like0Like0Like0Like0Like0Like0Like1Like0Like0Like0Like0Like0Like0