Skip to content

Instantly share code, notes, and snippets.

@ELLIOTTCABLE
Forked from Mikoangelo/wrapwrapwrap!.rb
Created August 13, 2008 02:15
Show Gist options
  • Save ELLIOTTCABLE/5181 to your computer and use it in GitHub Desktop.
Save ELLIOTTCABLE/5181 to your computer and use it in GitHub Desktop.
--------------------------------------------------------------------------------| <-- 81
»Hey, Danny! Why don't you just go,« he asked teasingly. His little brother |
stood only fifty feet from him. The ideal distance, he thought. No, he didn't |
think. He hadn't thought for the last two years of his life. He knew. |
|
»Why don't you just go?« He repeated the taunt, knowing full well what his two |
years younger sibling was thinking. Ever since kindergarten, he had been a |
little distanced from the world, as if he lived slightly out of phase with it. |
As if only a fraction of the world's truths were real to him. |
|
He was always entranced by a movie, a comic, a sci-fi book, a cartoon. Always |
just sitting, never talking -- but always getting mom's attention. |
|
»Mom said not to go over the street until it's empty,« Danny replied, having |
trouble getting his 9-year-old voice to be audible over the noise of the street.|
He looked at his brother standing against the lamp-post, wondering why he didn't|
come nearer. As usual, when something didn't make sense to him, he discarded it |
as his own silliness. That's what mom had always said. |
|
»Look, the car's aren't gonna hurt you. Haven't you watched cartoons?« Danny |
loved watching Road Runner. |
|
»It's your first day alone in traffic, do you really wanna make everyone think |
you're bad at it?« |
|
»Are you sure? Mom said ...« |
|
»Of course I'm sure.« He said it with a light, slightly worried laugh, and a |
shake of the head. Why would he do that? He was behaving very oddly. |
|
»But what'll happen if a car hits me? Wouldn't it hurt?« |
|
»I told you, it won't hurt!« |
|
»Well, okay then ...« He pulled his bike a little forward under him, and started|
moving forward. |
|
»Now,« the older brother said, with a weird intonation of his voice -- almost as|
if he was scared. The younger didn't know it was a cover, the older played the |
part too well. |
|
»Just go!« He shouted, and started running at his brother, looking positively |
frightened. |
|
It made no sense to Danny, so he turned his head to see what his brother was |
doing.
# ---- -- ---- stringray.rb ---- -- ----
module StringRay
VERSION = 2
# Splits a string into words. Not using the obvious names (+#split+, +#words+)
# because I want compatibility for inclusion into +String+.
def enumerate
ray = []
self.each_byte do |byte|
char = byte.chr
if Delimiter::Characters.include? char
ray << Delimiter.new(char)
elsif Whitespace::Characters.include? char
if ray.last.is_a? Whitespace
ray.last << char
else
ray << Whitespace.new(char)
end
else
if ray.last.is_a? Word
ray.last << char
else
ray << Word.new(char)
end
end
end
ray
end
# More sensible than +String#each+, this uses +#enumerate+ to enumerate on
# words. Accepts options as a hash, determining whether :whitespace and
# :delemiters will :attach_before, :standalone, or :attach_after. Default is
# for both to :attach_before.
def each_word opts = {}, &block
{:whitespace => :attach_before, :delemiters => :attach_before}.merge! opts
# First, we create a two-dimensional array of words with any whitespace or
# delemiters that should attach to them.
words = self.enumerate
mapped = []
attach_before_next = []
words.each do |item|
case item
when Delimiter
case opts[:delemiters]
when :standalone
mapped << [item]
when :attach_after
attach_before_next << item
else
if attach_before_next.empty?
if mapped.last
mapped.last << item
else
attach_before_next << item
end
else
attach_before_next << item
end
end
when Whitespace
case opts[:whitespace]
when :standalone
mapped << [item]
when :attach_after
attach_before_next << item
else
if attach_before_next.empty?
if mapped.last
mapped.last << item
else
attach_before_next << item
end
else
attach_before_next << item
end
end
when Word
if not attach_before_next.empty?
mapped << [attach_before_next, item].flatten
attach_before_next = []
else
mapped << [item]
end
end
end
(mapped.last << attach_before_next).flatten! if not attach_before_next.empty?
# Next, we yield each group of (word plus delimiters and whitespace) as a
# normal string to the block
mapped.each do |arr|
yield arr.map{|w|w.to_s}.join
end
end
class Word < String
def inspect
"(#{self})"
end
end
class Whitespace < String
Characters = [" ", "\t", "\n"]
def inspect
"#{self}"
end
end
class Delimiter < String
Characters = ['-', ',', '.', '?', '!', ':', ';', '/', '\\', '|']
def inspect
"<#{self}>"
end
end
# This overrides +String#each+ with +StringRay#each_word+, thus allowing us
# to include +Enumerable+.
def self.included klass
klass.class_eval do
alias_method :each_at, :each
alias_method :each, :each_word
include Enumerable
end
end
end
# ---- -- ---- string.rb ---- -- ----
class String
include StringRay
def indent spaces
if spaces.respond_to? :to_s # duck,
self.split("\n").map {|s| [spaces, s].join }.join("\n")
elsif spaces.respond_to? :to_i # duck,
self.split("\n").map {|s| [(' ' * spaces), s].join }.join("\n")
else # goose!
raise ArgumentError, "#{spaces} is neither string-ish nor numeric-ish"
end
end
# Simply returns an array of two string pieces split at +length+.
def split_at length
self.scan /.{1,#{length}}/u
end
# Fix ruby's problem with unicode compliant string lengths
def length
self.scan(/./um).size
end
# Wraps a string, *intelligently*
def wrap width, min = nil
raise ArgumentError, "#{width} is not numeric-ish" unless width.respond_to? :to_i
min ||= (width.to_i * 0.75).to_i # Default to about a third of the full width
raise ArgumentError, "#{min} is not numeric-ish" unless min.respond_to? :to_i
self.split("\n").map do |line|
line.inject([""]) do |wrapped, word|
print "word: #{word.inspect}, current line: #{wrapped.last.inspect} "
# If we're still short enough to fit the word, do so
if wrapped.last.length + word.rstrip.length <= width
puts "- new length #{wrapped.last.length + word.rstrip.length} (#{wrapped.last.length} + #{word.rstrip.length}) is less than #{width}"
wrapped.last << word
# Else, if we're less than minimum width
elsif wrapped.last.length < min
puts "- new length #{wrapped.last.length + word.rstrip.length} (#{wrapped.last.length} + #{word.rstrip.length}) would be more than #{width}"
puts "- current length #{wrapped.last.length} is less than #{min}"
bits = word.split_at(width - wrapped.last.length)
wrapped.last << bits.shift
bits.join.split_at(width)
bits.each {|bit| wrapped << bit}
# Else if neither can fit on current line, nor is line short enough; and
# the word is short enough to fit on the new line
elsif word.chomp.length < width
puts "- new length #{wrapped.last.length + word.rstrip.length} (#{wrapped.last.length} + #{word.rstrip.length}) would be more than #{width}"
puts "- current length #{wrapped.last.length} is more than #{min}"
puts "- word's length #{word.chomp.length} is less than #{width}"
wrapped << word
# If it can't fit on the current line, and it can't fit wholly on a line
# by it's own
else
puts "- new length #{wrapped.last.length + word.rstrip.length} (#{wrapped.last.length} + #{word.rstrip.length}) would be more than #{width}"
puts "- current length #{wrapped.last.length} is more than #{min}"
puts "- word's length #{word.chomp.length} is more than #{width}"
bits = word.split_at(width)
bits.each {|bit| wrapped << bit}
end
wrapped
end.join("\n")
end.join("\n")
end
end
# ---- -- ---- wrap_test.rb ---- -- ----
puts DATA.read.wrap(80).gsub(/(.*)\n/u) {|line|
$1.rstrip + (' ' * (80 - line.rstrip.length)) + "|\n"
}
puts ('-' * 80) + '| <-- 81'
__END__
»Hey, Danny! Why don't you just go,« he asked teasingly. His little brother stood only fifty feet from him. The ideal distance, he thought. No, he didn't think. He hadn't thought for the last two years of his life. He knew.
»Why don't you just go?« He repeated the taunt, knowing full well what his two years younger sibling was thinking. Ever since kindergarten, he had been a little distanced from the world, as if he lived slightly out of phase with it. As if only a fraction of the world's truths were real to him.
He was always entranced by a movie, a comic, a sci-fi book, a cartoon. Always just sitting, never talking -- but always getting mom's attention.
»Mom said not to go over the street until it's empty,« Danny replied, having trouble getting his 9-year-old voice to be audible over the noise of the street. He looked at his brother standing against the lamp-post, wondering why he didn't come nearer. As usual, when something didn't make sense to him, he discarded it as his own silliness. That's what mom had always said.
»Look, the car's aren't gonna hurt you. Haven't you watched cartoons?« Danny loved watching Road Runner.
»It's your first day alone in traffic, do you really wanna make everyone think you're bad at it?«
»Are you sure? Mom said ...«
»Of course I'm sure.« He said it with a light, slightly worried laugh, and a shake of the head. Why would he do that? He was behaving very oddly.
»But what'll happen if a car hits me? Wouldn't it hurt?«
»I told you, it won't hurt!«
»Well, okay then ...« He pulled his bike a little forward under him, and started moving forward.
»Now,« the older brother said, with a weird intonation of his voice -- almost as if he was scared. The younger didn't know it was a cover, the older played the part too well.
»Just go!« He shouted, and started running at his brother, looking positively frightened.
It made no sense to Danny, so he turned his head to see what his brother was doing.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment