An itty-bitty extension that adds gradient method to String class that supports any hex colour, for Linux terminals only:
Add this line to your application's Gemfile:
gem 'string_dot_gradient'
And then execute:
$ bundle install
Or install it yourself as:
$ gem install string_dot_gradient
irb
irb(main):001:0> require 'string_dot_gradient'
=> true
irb(main):002:0> puts 'abcdefgh'.gradient('ff5', '55f')
abcdefgh
=> nil
irb(main):003:0> puts 'abcdefgh'.gradient(0xffff55, 0x5555ff)
abcdefgh
=> nil
This actually generates ANSI sequences to create gradient colours:
irb(main):004:0> 'abcdefgh'.gradient('ff5', '55f')
=> "\e[38;2;223;223;116ma\e[38;2;191;191;148mb\e[38;2;159;159;180mc\e[38;2;127;127;212md\e[38;2;95;95;244me\e[38;2;63;63;255mf\e[38;2;31;31;255mg\e[38;2;0;0;255mh\e[0m"
irb(main):005:0> 'abcdefgh'.gradient(0xff5555, 0x5555ff)
=> "\e[38;2;223;223;116ma\e[38;2;191;191;148mb\e[38;2;159;159;180mc\e[38;2;127;127;212md\e[38;2;95;95;244me\e[38;2;63;63;255mf\e[38;2;31;31;255mg\e[38;2;0;0;255mh\e[0m"
puts "Hello 🐵\nI am using string_dot_gradient!\nLove this gem!".gradient('f55', '55f', '3eb', 'f5f')
def gradient(*arg_colours,
exclude_spaces: true,
bg: false,
bold: false,
blink: false,
underline: false,
double_underline: false,
overline: false,
italic: false,
strikethrough: false
)
Do note that the strikethrough, overline, double_underline may not work on every terminal. The blink might not work on terminals that don't implement cursor blinking (integrated terminals in some IDE for example)
- #f55
- #ff5555
- f55
- ff5555
- 0xff5555
When an integer colour is passed, the conversion will be faster than a string parsing.
- For example: 0xffffff for white,
- 0x000000 or 0x0 for black, 0x00aa00 for deep green
- 0xff50a6 for pink, 0xff5555 for light red, etc.
Similarly you can use Integers directly (not recommended though):
- (255 * 256 * 256) + (255 * 256) + (255) => 0xffffff
- (0 * 256 * 256) + (0 * 256) + 0 => 0x0
- (255 * 256 * 256) + (85 * 256) + 85 => #ff5555
- (85 * 256 * 256) + (85 * 256) + 255 => #5555ff
- (255 * 256 * 256) + (170 * 256) + 0 => 0xffaa00
- (0 * 256 * 256) + (170 * 256) + 0 => 0x00aa00
- Using any bad Integer can do the following:
- 0x00aa00aa00aa (any big Integer) will be aa00aa, clamping to last 6 hex digits.
- 0x0a0 (hex < 6 digit) will be 0000a0, shifting the value to right.
- Negative Integer will cause unexpected output, but won't cause any major crash.
- Any bad String colour that's out of hex range, will raise ArgumentError.
'Hello world this is multi_gradient()'.multi_gradient('3eb', '55f', 'f55', 'fa0')
"Hello world\nthis is multi_gradient()".multi_gradient('3eb', '55f', 'f55', 'fa0')
# Or #
'Hello world this is multi_gradient()'.multi_gradient(0x33eebb, 0x5555ff, 0xff5555, 0xffaa00)
'Hello world\nthis is multi_gradient()'.multi_gradient(0x33eebb, 0x5555ff, 0xff5555, 0xffaa00)
You can pass N number of colours to multigradient, and prints that in one line. multi_gradient() also accepts, bold, blink, underline, etc options that gradient() accepts.
Do note that multiline colours will not get rotated like String#gradient(), but will be applied to each line instead.
Sometimes it can be time-consuming for a very big string. Also, this could consume a lot of memory. Just take a look at the return value of "abcdefgh" above, you know it has a lot of extra characters!
To prevent creating a new string, and yield whatever is getting processed, use a block.
You can use printf and whatnot in that block. For example:
$ irb
irb(main):001:0> require 'string_dot_gradient'
=> true
irb(main):002:0> "Hello\nWorld".gradient(0xff5555, 0x5555ff) { |x| print x }
Hello
World=> nil
irb(main):003:0> "Hello\nWorld".gradient('#f55', '#55f') { }
=> nil
As you can see, it returns nil, but the value of the string is yielded to the block variable instead. This makes it consume way lesser memory.
You can animate your text using blocks!
Here's an example:
Code used:
require 'io/console'
require 'string_dot_gradient'
w = STDOUT.winsize[1] - 4
i = -1
story = <<~'EOF'.gsub(?\n, ?\s)
Four cows lived in a forest near a meadow. They were good friends and did
everything together. They grazed together and stayed together, because of
which no tigers or lions were able to kill them for food. But one day, the friends
fought and each cow went to graze in a different direction. A tiger and a lion saw
this and decided that it was the perfect opportunity to kill the cows. They hid in
the bushes and surprised the cows and killed them all, one by one.
EOF
# Adding new lines to the story based on the terminal size
story_with_newline = story.chars.each { |x|
i += 1
# Check if the w-th character exceeds the terminal size or not
# If it exceeds the size, add a new line in the story
if i > w || i > w - 6 && x == ?\s.freeze
x.rstrip!
x << ?\n.freeze
i = 0
end
}.join
story_with_newline.gradient('f55', '55f', '3eb', 'fa0', 'ff50a6', 'ff0') { |x|
print x
sleep 0.01
}
puts
[ Story from: https://moralstories.top/read/the-cows-and-the-tiger ]
You can also use multi_gradient() and pass blocks, to yield the characters to the block instead.
A string can contain spaces or tabs, to exclude them, use the exclude_spaces optional. Set it to true or false. A truthy or falsey value will also work, but it's not recommended.
- if exclude_spaces is set to true, it will not waste colours on spaces and tabs
- if exclude_spaces is set to false, it will waste colours on spaces and tabs
After checking out the repo, run bin/setup
to install dependencies.
You can also run bin/console
for an interactive prompt that will allow you to experiment.
Bug reports and pull requests are welcome on GitHub at https://github.com/Souravgoswami/string_dot_gradient.
The gem is available as open-source under the terms of the MIT License.