Skip to content

Commit

Permalink
util-app: improve c.t.a.Flag usage by providing a 'letParse' method
Browse files Browse the repository at this point in the history
Problem

If a `Flag` is used in a manner that results in type erasure (i.e. contained
within a collection of `Flag`), there is no way of using a `Flag.let` without
knowing the `Flag`'s `T` type.

Solution

Introduce a `letParse` method, which will use the underlying `flaggable` to
parse and `let` using the correct type associated with the `Flag`.

Result

Users of Flags can now call `letParse` without needing to explicitly know
or reference the Flag's `T: Flaggable` type.

JIRA Issues: CSL-7824

Differential Revision: https://phabricator.twitter.biz/D288549
  • Loading branch information
enbnt authored and jenkins committed Mar 21, 2019
1 parent db8ad2a commit 0d9dded
Show file tree
Hide file tree
Showing 3 changed files with 50 additions and 0 deletions.
6 changes: 6 additions & 0 deletions CHANGELOG.rst
Expand Up @@ -7,6 +7,12 @@ Note that ``PHAB_ID=#`` and ``RB_ID=#`` correspond to associated messages in com
Unreleased
----------

New Features
~~~~~~~~~~~~

* util-app: Improve usage of `Flag.let` by providing a `Flag.letParse` method
``PHAB_ID=D288549``

19.3.0
------

Expand Down
12 changes: 12 additions & 0 deletions util-app/src/main/scala/com/twitter/app/Flag.scala
Expand Up @@ -146,17 +146,29 @@ class Flag[T: Flaggable] private[app] (
* Override the value of this flag with `t`, only for the scope of the current
* [[com.twitter.util.Local]] for the given function `f`.
*
* @see [[letParse]]
* @see [[letClear]]
*/
def let[R](t: T)(f: => R): R =
let(Some(t), f)

/**
* Override the value of this flag with `arg` [[String] parsed to this [[Flag]]'s [[T]] type,
* only for the scope of the current [[com.twitter.util.Local]] for the given function `f`.
*
* @see [[let]]
* @see [[letClear]]
*/
def letParse[R](arg: String)(f: => R): R =
let(flaggable.parse(arg))(f)

/**
* Unset the value of this flag, such that [[isDefined]] will return `false`,
* only for the scope of the current [[com.twitter.util.Local]] for the
* given function `f`.
*
* @see [[let]]
* @see [[letParse]]
*/
def letClear[R](f: => R): R =
let(None, f)
Expand Down
32 changes: 32 additions & 0 deletions util-app/src/test/scala/com/twitter/app/FlagTest.scala
Expand Up @@ -86,6 +86,38 @@ class FlagTest extends FunSuite {
assert(res2 == "false")
}

test("Flag: letParse") {
def current: Boolean = MyGlobalBooleanFlag()

// track the order the blocks execute and that they only execute once
var buf = mutable.Buffer[Int]()

// make sure they stack properly
assert(!current)
MyGlobalBooleanFlag.letParse("true") {
buf += 1
assert(current)
MyGlobalBooleanFlag.letParse("false") {
buf += 2
assert(!current)
}
buf += 3
assert(current)
}
assert(!current)

assert(buf == Seq(1, 2, 3))
}

test("Flag: letParse return values reflect bindings") {
def current: Boolean = MyGlobalBooleanFlag()

val res1 = MyGlobalBooleanFlag.letParse("true") { current.toString }
assert(res1 == "true")
val res2 = MyGlobalBooleanFlag.letParse("false") { current.toString }
assert(res2 == "false")
}

test("Flag: letClear") {
// track the order the blocks execute and that they only execute once
var buf = mutable.Buffer[Int]()
Expand Down

0 comments on commit 0d9dded

Please sign in to comment.