class Montoc::DocBox
Attributes
Public Class Methods
# File lib/montoc.rb, line 27 def self.know docbox fresh_key = docbox.object_id.to_s(36).to_sym @original_text[fresh_key] = docbox.instance_eval {@text} end
# File lib/montoc.rb, line 10 def initialize text = "" @text = text @format = :virgin yield self if block_given? DocBox.know self end
# File lib/montoc.rb, line 32 def self.recall docbox fresh_key = docbox.object_id.to_s(36).to_sym return @original_text[fresh_key] end
Public Instance Methods
# File lib/montoc.rb, line 37 def + string @text = squeeze_space @text << string.to_s @format = :left if @format == :virgin method(@format.id2name + "!").call return self end
# File lib/montoc.rb, line 189 def center new_text = squeeze_space.split("\n").map do |line| line = line.chomp.strip.rjust columns-(columns-line.length)/2 line = line.ljust columns end .join "\n" return DocBox.new(new_text) end
Find the contents of a specific column of a text. @note Should be used in matricized text, otherwise it could return some
nil even though the column number specified less than the longest line. The specified number should start from 1 to number of columns. It will return nil if it's more than the total number of columns and raise ArgumentError if lower than 1.
@param col_no [Fixnum] Specific column number, between 1 and total number
of rows.
@return [String] Return string at specified column of matricized text
# File lib/montoc.rb, line 99 def column col_no = 1 raise ArgumentError, "Column number cannot be lower than 1." \ if col_no < 1 matricize if col_no > columns return nil end column_text = "" @text.each_line do |line| column_text << line.to_s.chomp[col_no-1] end return column_text end
Find the length of the longest line or number of columns in a matricized text. @return [Fixnum] Number of columns in a text
# File lib/montoc.rb, line 86 def columns return longest_line.length end
# File lib/montoc.rb, line 251 def justify left_align_EOP = true spacing_priority = {} space_weight.each do |line, weights| spacing_priority[line] = weights.sort_by do |position, weight| weight end .reverse.to_h.map do |position, weight| position end end # Result example: # {0=>[2, 0, 1], 1=>[1, 0], 2=>[0], 3=>[2, 1, 0], 4=>[0]} squeezed_text = squeeze_space end_of_para = [] # Get lines that end paragraphs squeezed_text.each_line.with_index do |line, line_index| if line =~ /^\s*$/ && line_index != 0 end_of_para.push(line_index - 1) end end inter_text = "" squeezed_text.each_line.with_index do |line, line_index| words_arr = line.split words_arr_length = words_arr.length < 2 ? 1 : words_arr.length-1 spaces_arr = (" ,"*words_arr_length).split(",") space_needed = columns-line.tr("\n", "").length (0...space_needed).each do |i| spaces_arr.length == 0 ? index = i : index = i % spaces_arr.length spaces_arr[spacing_priority[line_index][index]] += " " end (0...words_arr.length).each do |j| inter_text << words_arr[j] inter_text << spaces_arr[j] unless j == words_arr.length - 1 end inter_text << "\n" end if left_align_EOP == true text_arr = inter_text.split("\n") inter_text.each_line.with_index do |line, line_index| if end_of_para.include?(line_index) || line == inter_text.lines[-1] text_arr[line_index] = line.strip.squeeze(" ").ljust(columns) end end inter_text = text_arr.join("\n") end new_text = "" inter_text.each_line do |line| line = line.tr("\n","") line = " ".ljust(columns) if line =~ /^\s*$/ new_text << line + "\n" end # In case line contains only one word, this will add trailing spaces newer_text = "" new_text.each_line do |line| newer_text << line.strip.ljust(columns) + "\n" end newer_text.chomp! # return new object with new text return DocBox.new(newer_text) end
# File lib/montoc.rb, line 319 def justify! left_align_EOP = true @text = justify(left_align_EOP).text @format = :justify return self end
# File lib/montoc.rb, line 175 def left new_text = squeeze_space.split("\n").map do |line| line = line.to_s.ljust columns end .join "\n" return DocBox.new(new_text) end
Find the longest lines in text and return the first match. to_s
is called from the longest_line
to avoid chomp being called from nil, in the case of text = “” @note Should be used when the @format is still in the :virgin state. @return [String] Return the first longest line in text
# File lib/montoc.rb, line 55 def longest_line longest_line = squeeze_space.lines.max_by(&:length) longest_line = longest_line.to_s.chomp return longest_line end
# File lib/montoc.rb, line 325 def longest_word longest_word = squeeze_space.split.max_by(&:length) return longest_word end
Make the object plain text into a rectangular (two dimensional
matrix) text by filling the empty spaces with spaces.
@note This will do nothing if the text is already a matrix @param align [Symbol] The alignment or format state, the default
is `:left`
@param columns [Fixnum] Number of columns to which the plain text
converted.
@return [DocBox, nil] The DocBox
object after the content/text made
into matrix or nil if the text is already a matrix before this method called.
# File lib/montoc.rb, line 123 def matricize align = :left, column_width = 72 if !matrix? reflow! column_width method(align.id2name + "!").call end end
Force making/remaking an object text into a matrix no matter it’s already a matrix or not. @param (see matricize
) @return [DocBox] The DocBox
object after the content/text made into
matrix.
# File lib/montoc.rb, line 135 def matricize! align = :left, column_width = 72 squeeze_space! matricize align, column_width end
Make two dimensional array of chars from the current object text @param (see matricize
) @return [Array] Return two dimensional array of chars from the
current object text
# File lib/montoc.rb, line 154 def matrix align = :left, columns = 72 matricize align, columns matrix_arr = [] @text.each_line.with_index do |line, index| matrix_arr[index] = line.chomp.split("") end return matrix_arr end
Check if the object text is already a matrix. @return [Boolean] Return ‘true` if the text already a matrix and
`false` if not.
# File lib/montoc.rb, line 143 def matrix? @text.each_line do |line| return false if line.to_s.chomp.length != columns end return true end
# File lib/montoc.rb, line 330 def reflow column_width = 72 raise ArgumentError, "Columns cannot be shorter than the longest word." \ if columns < longest_word.length new_text = "" text_arr = @text.split(/\n\s*\n/) new_paragraph = [] text_arr.each do |paragraph| para = [] para_arr = paragraph.split(" ") while para_arr.length > 0 line_arr = [] para_arr.take_while do |word| line_arr.push(word) line_arr.join(" ").length <= column_width end line_arr.pop if line_arr.join(" ").length > column_width len = line_arr.length para_arr.shift(len) line = line_arr.join(" ") para << line + " \n" end new_paragraph << para.join end new_text = new_paragraph.join("\n") unless @format == :virgin new_text = DocBox.new(new_text).method(@format).call.text else return DocBox.new(new_text).left # default alignment end return DocBox.new(new_text) end
# File lib/montoc.rb, line 364 def reflow! column_width = 72 obj = reflow(column_width) @text = obj.text @format = obj.format return self end
# File lib/montoc.rb, line 182 def right new_text = squeeze_space.split("\n").map do |line| line = line.chomp.strip.rjust columns end .join "\n" return DocBox.new(new_text) end
Find the contents of a specific row or line of a text. @note The specified number should start from 1 to number of rows. It will
return nil if it's more than the total number of rows and raise ArgumentError if lower than 1.
@param row_no [Fixnum] Specific row number, between 1 and total number
of rows.
@return [String] Return line at specified row
# File lib/montoc.rb, line 75 def row row_no = 1 raise ArgumentError, "Row number cannot be lower than 1." \ if row_no < 1 matricize row_text = text.lines[row_no-1] return row_text end
Find the number of lines in a text or the number of rows if you see it as a two dimensional matrix of chars. @return [Fixnum] Number of lines in a text
# File lib/montoc.rb, line 64 def rows return @text.lines.length end
# File lib/montoc.rb, line 212 def space_weight # Initialize space position at line 0 as 0 space_weight = {0=>0} i = 0 squeeze_space.each_line do |line| # Initialize weight carried by a space at space position 0 as 0 weight = {0=>0} # Space position index in each line starting from 0 j = 0 # Capture weight carried by each space in each line # Weight means the total number of characters to the left and right # of a space. line.tr("\n","").split.each_cons(2) do |left_word, right_word| weight[j] = left_word.length + right_word.length if left_word # Move index to next space position j += 1 end # Copy space weight per line to overall space weight hash space_weight[i] = weight i +=1 end return space_weight # Return format: # {line number => {space number => weight, next space number => weight, ...}, # next line number => {space number => weight, ...}, # ...} # Return example: # {0=>{0=>6, 1=>3, 2=>8}, 1=>{0=>4, 1=>8}, 2=>{0=>0}, 3=>{0=>8, 1=>8, 2=>9}} # Meaning: # Line 0 has 3 spaces with the first and the last space has weight of 6 and # 8, respectively. Line 2 is an empty line. end
# File lib/montoc.rb, line 197 def squeeze_space inter_text = @text new_text = "".to_s # strip extra space between non-space characters inter_text.each_line do |line| new_text << line.strip.squeeze(" ") + "\n" end return new_text end
# File lib/montoc.rb, line 208 def squeeze_space! @text = squeeze_space end
# File lib/montoc.rb, line 45 def text= string @text = string DocBox.know self end
Override Object#to_s, so that puts or other methods call this method to get the string representation of this object
@return [String] Return @text as the string representation of
DocBox object.
# File lib/montoc.rb, line 22 def to_s return @text end
# File lib/montoc.rb, line 169 def virgin? return true if @format == :virgin return false end
# File lib/montoc.rb, line 163 def virginize @format = :virgin @text = DocBox.recall self return self end