+ # Returns `self` removed from its last line terminator (if any).
+ #
+ # assert "Hello\n".chomp == "Hello"
+ # assert "Hello".chomp == "Hello"
+ #
+ # assert "\n".chomp == ""
+ # assert "".chomp == ""
+ #
+ # Line terminators are `"\n"`, `"\r\n"` and `"\r"`.
+ # A single line terminator, the last one, is removed.
+ #
+ # assert "\r\n".chomp == ""
+ # assert "\r\n\n".chomp == "\r\n"
+ # assert "\r\n\r\n".chomp == "\r\n"
+ # assert "\r\n\r".chomp == "\r\n"
+ #
+ # Note: unlike with most IO methods like `IStream::read_line`,
+ # a single `\r` is considered here to be a line terminator and will be removed.
+ fun chomp: SELFTYPE
+ do
+ var len = length
+ if len == 0 then return self
+ var l = self.chars.last
+ if l == '\r' then
+ return substring(0, len-1)
+ else if l != '\n' then
+ return self
+ else if len > 1 and self.chars[len-2] == '\r' then
+ return substring(0, len-2)
+ else
+ return substring(0, len-1)
+ end
+ end
+
+ # Justify a self in a space of `length`
+ #
+ # `left` is the space ratio on the left side.
+ # * 0.0 for left-justified (no space at the left)
+ # * 1.0 for right-justified (all spaces at the left)
+ # * 0.5 for centered (half the spaces at the left)
+ #
+ # Examples
+ #
+ # assert "hello".justify(10, 0.0) == "hello "
+ # assert "hello".justify(10, 1.0) == " hello"
+ # assert "hello".justify(10, 0.5) == " hello "
+ #
+ # If `length` is not enough, `self` is returned as is.
+ #
+ # assert "hello".justify(2, 0.0) == "hello"
+ #
+ # REQUIRE: `left >= 0.0 and left <= 1.0`
+ # ENSURE: `self.length <= length implies result.length == length`
+ # ENSURE: `self.length >= length implies result == self`
+ fun justify(length: Int, left: Float): SELFTYPE
+ do
+ var diff = length - self.length
+ if diff <= 0 then return self
+ assert left >= 0.0 and left <= 1.0
+ var before = (diff.to_f * left).to_i
+ return " " * before + self + " " * (diff-before)
+ end
+
+ # Mangle a string to be a unique string only made of alphanumeric characters and underscores.
+ #
+ # This method is injective (two different inputs never produce the same
+ # output) and the returned string always respect the following rules:
+ #
+ # * Contains only US-ASCII letters, digits and underscores.
+ # * Never starts with a digit.
+ # * Never contains two contiguous underscores.
+ #
+ # assert "42_is/The answer!".to_cmangle == "_52d2_is_47dThe_32danswer_33d"
+ # assert "__d".to_cmangle == "_95d_d"
+ # assert "_42".to_cmangle == "_95d42"
+ # assert "foo".to_cmangle == "foo"
+ # assert "".to_cmangle == ""