#!/usr/bin/ruby
# Author: Daniel "Trizen" Șuteu
# License: GPLv3
# Date: 15th October 2013
# Translated to Sidef in 17 June 2015
# https://trizenx.blogspot.com
# Smart word wrap algorithm
# See: https://en.wikipedia.org/wiki/Word_wrap#Minimum_raggedness
# Review: https://trizenx.blogspot.ro/2013/11/smart-word-wrap.html
class SmartWordWrap(WIDTH=80) {
method prepare_words(array) {
var root = [];
var len = 0;
for (var i = 0 ; i <= array.end ; i++) {
var word_len = array[i].len;
len += word_len;
len > WIDTH && (
word_len > WIDTH && (
len -= word_len;
array.splice(i, 1, array[i].split(WIDTH)...);
--i; next;
);
break;
);
root.append(Hash(array.slice(0, i+1).join(" ") => self.prepare_words(array.slice(i+1))))
++len >= WIDTH && break;
}
root ? root : null;
}
method combine(root, hash) {
var row = [];
hash.each { |key, value|
root.append(key);
if (value.is_an(Array)) {
value.each { |item|
row.append(self.combine(root, item)...);
}
}
else {
row = [[root...]];
}
root.pop;
}
row;
}
method find_best(arrays) {
var best = Hash.new(
score => Inf,
value => [],
);
arrays.each { |array_ref|
var score = 0;
array_ref.each { |string|
score += ::pow(WIDTH - string.len, 2);
}
score < best{:score} && (
best{:score} = score;
best{:value} = array_ref;
);
}
best{:value};
}
method wrap(text, width) {
# Temporarily modify the width
local WIDTH = width if defined(width);
# Split the text into words
text.is_a(String) && text.words!;
var lines = [];
self.prepare_words(text).each { |path|
lines.append(self.combine([], path)...);
}
self.find_best(lines).join("\n");
}
}
var sww = SmartWordWrap();
var words = %w(aaa bb cc ddddd);
#var words = %w(Lorem ipsum dolor sit amet, consectetur adipiscing elit.);
var wrapped = sww.wrap(words, 6);
say wrapped;
wrapped == ['aaa', 'bb cc', 'ddddd'].join("\n") || die "error!";