# \[Proposal\] ActiveSupport or\_else

**URL:** <https://discuss.rubyonrails.org/t/proposal-activesupport-or-else/81315>\
**Category:** rubyonrails-core\
**Tags:** activesupport\
**Created:** [August 25, 2022, 7:23pm UTC](https://discuss.rubyonrails.org/t/proposal-activesupport-or-else/81315 "2022-08-25T19:23:59Z")\
**Posts on this page:** 6\
**Page:** 1

<div class="post-metadata">

**Author:** ![jharrilim](https://sea2.discourse-cdn.com/rubyonrails/user_avatar/discuss.rubyonrails.org/jharrilim/32/5644_2.png) [@jharrilim](https://discuss.rubyonrails.org/u/jharrilim)\
**Post date:** [August 25, 2022, 7:23pm UTC](https://discuss.rubyonrails.org/t/proposal-activesupport-or-else/81315/1 "2022-08-25T19:23:59Z")

</div>

This would allow some cleaner expressions by allowing us to remove some outer parentheses.

This:

```ruby
def one_of(possibilities = [])
  (possibilities.find(&:present?) || "").split(",").first.try(:strip) || ""
end

```

Becomes:

```ruby
def one_of(possibilities = [])
  possibilities.find(&:present?).or_else("").split(",").first.try(:strip).or_else("")
end

```

* * *

This code would go into `Object` and `NilClass`. Perhaps something like this:

```ruby
class Object
  def or_else(default_value)
    present? ? self : default_value
  end
end

class NilClass
  def or_else(default_value)
    default_value
  end
end

```

* * *

edit 1:

I’d also propose having a block variant as well. This would make the API a bit more useful, and a bit more like the inverse of the `try` API.

Similar to how we can have:

```ruby
Person.find_by(name: params[:name]).try do |person|
  # do things with person
end

```

We would be able to handle the non-existing case:

```ruby
Person.find_by(name: params[:name]).try(:touch).or_else do
  MissingPersonReportJob.perform_later(params[:name])
end

```

Also, `try` + `or_else` is useful for non-activerecord objects. Whereas ActiveRecord has APIs such as `find_or_create_by`, plain objects can have `or_else`.

Slightly contrived, but an example would be:

```ruby
DEFAULT_VALUES = { a: 1, b: 2 }
# Process a JSON response from an external API.
# Necessary since we don't own the API and can't
# make changes directly to it
# @param [Hash, NilClass] hash
def process_a_json_response(hash)
  hash.try(:merge, DEFAULT_VALUES)
      .or_else(DEFAULT_VALUES)
end

```

---

<div class="post-metadata">

**Author:** ![e\_a](https://avatars.discourse-cdn.com/v4/letter/e/9fc348/32.png) [@e\_a](https://discuss.rubyonrails.org/u/e_a)\
**Post date:** [August 26, 2022, 2:47pm UTC](https://discuss.rubyonrails.org/t/proposal-activesupport-or-else/81315/2 "2022-08-26T14:47:28Z")

</div>

I’m not sure I really follow what your `one_of` method is doing. The name sort of implies it should behave like [`in?`](https://api.rubyonrails.org/classes/Object.html#method-i-in-3F) but it doesn’t.

As to your actual proposal of `of_else` this seems vaguely like the [`presence`](https://api.rubyonrails.org/classes/Object.html#method-i-presence). I.E.

```ruby
variable.presence || 'default'

```

would be the same as your:

```ruby
variable.or_else(default)

```

You said your goal is to remove parens but seems like both methods have the same number of parens if you wanted to chain additional methods just in different locations. I.E.

```ruby
(variable.presence || '').split(',')

```

vs

```ruby
variable.or_else('').split(',')

```

Just my two cents. Others may have different opinions.

---

<div class="post-metadata">

**Author:** ![nikita](https://sea2.discourse-cdn.com/rubyonrails/user_avatar/discuss.rubyonrails.org/nikita/32/5647_2.png) [@nikita](https://discuss.rubyonrails.org/u/nikita)\
**Post date:** [August 26, 2022, 2:58pm UTC](https://discuss.rubyonrails.org/t/proposal-activesupport-or-else/81315/3 "2022-08-26T14:58:37Z")

</div>

Definitely not opposed to this suggestion, just wanted to say that I’d be curious to see a few more examples of where the proposed method could be used as in my opinion the shared example is hard to approach from reading point of view in both of the versions.

Currently it’s a one-liner that performs some transformations on primitives which makes it really hard to make assumptions about the code or learn the context.

I think in a real application I’d prefer splitting it into several methods with guard clauses and descriptive names that represent some concepts from my app

This is still far from being accessible but I believe it reveals opportunities to extract some concepts into separate methods

```ruby
def one_of(possibilities = [])
  possibilities.compact!
  return "" if possibilities.empty?

  possibility = possibilities.first

  first_possibility_component = possibility.split(",").first

  return "" unless first_possibility_component

  first_possibility_component.strip
end

```

---

<div class="post-metadata">

**Author:** ![jharrilim](https://sea2.discourse-cdn.com/rubyonrails/user_avatar/discuss.rubyonrails.org/jharrilim/32/5644_2.png) [@jharrilim](https://discuss.rubyonrails.org/u/jharrilim)\
**Post date:** [August 29, 2022, 2:11pm UTC](https://discuss.rubyonrails.org/t/proposal-activesupport-or-else/81315/4 "2022-08-29T14:11:50Z")

</div>

> As to your actual proposal of `of_else` this seems vaguely like the [`presence`](https://api.rubyonrails.org/classes/Object.html#method-i-presence). I.E.

Indeed! I would even like for it to use presence within the implementation.

> You said your goal is to remove parens but seems like both methods have the same number of parens

To be clear, I want to remove _outer_ parentheses. This makes the chain of calls clearer, especially across multiple lines in a codebase with aligned method chains:

```ruby
(variable.presence || '')
         .split(',') # should it be indented to this point?
         .first
         .try(:strip) || '' # this also feels sort of awkward

```

vs:

```ruby
variable.or_else('')
        .split(',')
        .first
        .try(:strip)
        .or_else('')

```

---

<div class="post-metadata">

**Author:** ![etherbob](https://avatars.discourse-cdn.com/v4/letter/e/ea666f/32.png) [@etherbob](https://discuss.rubyonrails.org/u/etherbob)\
**Post date:** [August 29, 2022, 9:57pm UTC](https://discuss.rubyonrails.org/t/proposal-activesupport-or-else/81315/5 "2022-08-29T21:57:33Z")

</div>

To be fair the example could also be written as

```ruby
variable.presence
            &.split(',')
            &.first
            &.strip || ''

```

but it still doesn’t align as nicely as your second version.

An alternative might be to add an argument to `presence` similar to `Hash#fetch`’s default

---

<div class="post-metadata">

**Author:** ![etherbob](https://avatars.discourse-cdn.com/v4/letter/e/ea666f/32.png) [@etherbob](https://discuss.rubyonrails.org/u/etherbob)\
**Post date:** [September 22, 2022, 4:31pm UTC](https://discuss.rubyonrails.org/t/proposal-activesupport-or-else/81315/6 "2022-09-22T16:31:19Z")

</div>

```ruby
variable.presence('')
        .split(',')
        .first
        .presence('')
        .strip

```
