Class: Tabula::Line

Inherits:
Rectangle show all
Defined in:
lib/tabula/text/line.rb

Overview

Represents a line of text (a row of text chunks). Used for grouping text elements that share the same vertical position.

Constant Summary

Constants inherited from Rectangle

Rectangle::VERTICAL_COMPARISON_THRESHOLD

Instance Attribute Summary collapse

Attributes inherited from Rectangle

#height, #left, #top, #width

Instance Method Summary collapse

Methods inherited from Rectangle

#<=>, #==, #area, #bottom, #bottom=, bounding_box_of, #bounds, #center, #contains?, #contains_point?, #dup, from_bounds, from_points, #hash, #horizontal_overlap, #horizontally_overlaps?, #intersection, #intersects?, #merge, #merge!, #overlap_ratio, #points, #right, #right=, #vertical_overlap, #vertically_overlaps?, #x, #x=, #y, #y=

Constructor Details

#initialize ⇒ Line

Returns a new instance of Line.



9
10
11
12
13
# File 'lib/tabula/text/line.rb', line 9

def initialize
  super(0, 0, 0, 0)
  @chunks = []
  @initialized = false
end

Instance Attribute Details

#chunks ⇒ Object (readonly)

Returns the value of attribute chunks.



7
8
9
# File 'lib/tabula/text/line.rb', line 7

def chunks
  @chunks
end

Instance Method Details

#add_chunk(chunk) ⇒ Object

Add a text chunk to this line

Parameters:



17
18
19
20
21
22
23
24
25
26
27
28
29
# File 'lib/tabula/text/line.rb', line 17

def add_chunk(chunk)
  @chunks << chunk
  if @initialized
    merge!(chunk)
  else
    @top = chunk.top
    @left = chunk.left
    @width = chunk.width
    @height = chunk.height
    @initialized = true
  end
  self
end

#average_char_width ⇒ Float

Average character width in this line

Returns:

  • (Float)


71
72
73
74
75
76
77
# File 'lib/tabula/text/line.rb', line 71

def average_char_width
  elements = text_elements
  return 0.0 if elements.empty?

  total_width = elements.sum(&:width)
  total_width / elements.size
end

#empty? ⇒ Boolean

Returns:

  • (Boolean)


117
118
119
# File 'lib/tabula/text/line.rb', line 117

def empty?
  @chunks.empty?
end

#gap_positions(min_gap: nil) ⇒ Array<Float>

Find gap positions between chunks

Parameters:

  • min_gap (Float) (defaults to: nil) —

    minimum gap size

Returns:

  • (Array<Float>) —

    gap center positions



101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
# File 'lib/tabula/text/line.rb', line 101

def gap_positions(min_gap: nil)
  min_gap ||= average_char_width * 2
  gaps = []
  sorted = sorted_chunks

  sorted.each_cons(2) do |left_chunk, right_chunk|
    gap_start = left_chunk.right
    gap_end = right_chunk.left
    gap_size = gap_end - gap_start

    gaps << ((gap_start + gap_end) / 2.0) if gap_size >= min_gap
  end

  gaps
end

#in_gap?(x, min_gap: nil) ⇒ Boolean

Check if a position falls within a gap between chunks

Parameters:

  • x (Float) —

    horizontal position

  • min_gap (Float) (defaults to: nil) —

    minimum gap size

Returns:

  • (Boolean)


83
84
85
86
87
88
89
90
91
92
93
94
95
96
# File 'lib/tabula/text/line.rb', line 83

def in_gap?(x, min_gap: nil)
  min_gap ||= average_char_width * 0.5
  sorted = sorted_chunks

  sorted.each_cons(2) do |left_chunk, right_chunk|
    gap_start = left_chunk.right
    gap_end = right_chunk.left
    gap_size = gap_end - gap_start

    return true if x.between?(gap_start, gap_end) && gap_size >= min_gap
  end

  false
end

#inspect ⇒ Object



129
130
131
# File 'lib/tabula/text/line.rb', line 129

def inspect
  to_s
end

#ltr_dominant? ⇒ Boolean

Check if this line is LTR dominant

Returns:

  • (Boolean)


43
44
45
46
47
48
49
# File 'lib/tabula/text/line.rb', line 43

def ltr_dominant?
  return true if @chunks.empty?

  ltr_count = @chunks.count(&:ltr_dominant?)
  rtl_count = @chunks.count(&:rtl_dominant?)
  ltr_count >= rtl_count
end

#rtl_dominant? ⇒ Boolean

Check if this line is RTL dominant

Returns:

  • (Boolean)


52
53
54
# File 'lib/tabula/text/line.rb', line 52

def rtl_dominant?
  !ltr_dominant?
end

#size ⇒ Object



121
122
123
# File 'lib/tabula/text/line.rb', line 121

def size
  @chunks.size
end

#sorted_chunks ⇒ Array<TextChunk>

Get chunks sorted by horizontal position Respects RTL text direction when most chunks are RTL

Returns:



34
35
36
37
38
39
40
# File 'lib/tabula/text/line.rb', line 34

def sorted_chunks
  if rtl_dominant?
    @chunks.sort_by(&:left).reverse
  else
    @chunks.sort_by(&:left)
  end
end

#text(separator: ' ') ⇒ String

Get the combined text of all chunks

Parameters:

  • separator (String) (defaults to: ' ') —

    separator between chunks

Returns:

  • (String)


59
60
61
# File 'lib/tabula/text/line.rb', line 59

def text(separator: ' ')
  sorted_chunks.map(&:text).join(separator)
end

#text_elements ⇒ Array<TextElement>

Get text elements from all chunks

Returns:



65
66
67
# File 'lib/tabula/text/line.rb', line 65

def text_elements
  @chunks.flat_map(&:elements)
end

#to_s ⇒ Object



125
126
127
# File 'lib/tabula/text/line.rb', line 125

def to_s
  "Line[#{text.inspect}](#{left}, #{top}, #{width}, #{height})"
end