Class: Tins::LinesFile

Inherits:
Object show all
Includes:
Enumerable
Defined in:
lib/tins/lines_file.rb

Overview

Tins::LinesFile provides enhanced file line processing capabilities.

This class wraps file content in a way that allows for rich line-level operations, including tracking line numbers, filenames, and providing convenient navigation and matching methods. It’s particularly useful for log processing, configuration files, or any scenario where you need to work with structured text data while maintaining context about line positions.

Examples:

Basic usage

lines_file = Tins::LinesFile.for_filename('example.txt')
lines_file.each do |line|
  puts line.file_linenumber  # => "example.txt:1"
  puts line.line_number      # => 1
end

Line navigation and matching

lines_file = Tins::LinesFile.for_filename('example.txt')
lines_file.next!           # Move to next line
lines_file.match_forward(/pattern/)  # Match forward from current position

Defined Under Namespace

Modules: LineExtension

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(lines, line_number = nil) ⇒ LinesFile

Initialize a LinesFile with lines and optional starting line number.

Parameters:

  • lines (Array<String>)

    Array of line strings to process

  • line_number (Integer) (defaults to: nil)

    Starting line number (default: 1)



72
73
74
75
76
77
78
79
80
# File 'lib/tins/lines_file.rb', line 72

def initialize(lines, line_number = nil)
  @lines = lines
  @lines.each_with_index do |line, i|
    line.extend LineExtension
    line.instance_variable_set :@line_number, i + 1
    line.instance_variable_set :@lines_file, self
  end
  instance_variable_set :@line_number, line_number || (@lines.empty? ? 0 : 1)
end

Instance Attribute Details

#filenameString

Returns The filename associated with this LinesFile.

Returns:

  • (String)

    The filename associated with this LinesFile



83
84
85
# File 'lib/tins/lines_file.rb', line 83

def filename
  @filename
end

#line_numberInteger

Returns The current line number (1-based).

Returns:

  • (Integer)

    The current line number (1-based)



86
87
88
# File 'lib/tins/lines_file.rb', line 86

def line_number
  @line_number
end

Class Method Details

.for_file(file, line_number = nil) ⇒ LinesFile

Create a LinesFile instance from an already opened file.

Parameters:

  • file (File)

    An open File object to read from

  • line_number (Integer) (defaults to: nil)

    Starting line number (default: 1)

Returns:



53
54
55
56
57
# File 'lib/tins/lines_file.rb', line 53

def self.for_file(file, line_number = nil)
  obj = new(file.readlines, line_number)
  obj.filename = file.path
  obj
end

.for_filename(filename, line_number = nil) ⇒ LinesFile

Create a LinesFile instance from a filename.

Parameters:

  • filename (String)

    Path to the file to read

  • line_number (Integer) (defaults to: nil)

    Starting line number (default: 1)

Returns:



42
43
44
45
46
# File 'lib/tins/lines_file.rb', line 42

def self.for_filename(filename, line_number = nil)
  obj = new(File.readlines(filename), line_number)
  obj.filename = filename
  obj
end

.for_lines(lines, line_number = nil) ⇒ LinesFile

Create a LinesFile instance from an array of lines.

Parameters:

  • lines (Array<String>)

    Array of line strings

  • line_number (Integer) (defaults to: nil)

    Starting line number (default: 1)

Returns:



64
65
66
# File 'lib/tins/lines_file.rb', line 64

def self.for_lines(lines, line_number = nil)
  new(lines, line_number)
end

Instance Method Details

#each {|line| ... } ⇒ LinesFile

Iterate through all lines, setting the current line number for each.

Yields:

  • (line)

    Each line in the file

Yield Parameters:

  • line (String)

    The current line object with line metadata

Returns:



140
141
142
143
144
145
146
147
148
149
150
# File 'lib/tins/lines_file.rb', line 140

def each(&block)
  empty? and return self
  old_line_number = line_number
  1.upto(last_line_number) do |number|
    self.line_number = number
    block.call(line)
  end
  self
ensure
  self.line_number = old_line_number
end

#empty?Boolean

Returns True if the file has no lines.

Returns:

  • (Boolean)

    True if the file has no lines



131
132
133
# File 'lib/tins/lines_file.rb', line 131

def empty?
  @lines.empty?
end

#file_linenumberString

Returns Formatted filename and line number (e.g., “file.txt:5”).

Returns:

  • (String)

    Formatted filename and line number (e.g., “file.txt:5”)



160
161
162
# File 'lib/tins/lines_file.rb', line 160

def file_linenumber
  "#{filename}:#{line_number}"
end

#inspectString

Returns Detailed inspection string.

Returns:

  • (String)

    Detailed inspection string



198
199
200
# File 'lib/tins/lines_file.rb', line 198

def inspect
  "#<#{self.class}: #{to_s.inspect}>"
end

#last_line_numberInteger

Returns The total number of lines in this file.

Returns:

  • (Integer)

    The total number of lines in this file



126
127
128
# File 'lib/tins/lines_file.rb', line 126

def last_line_number
  @lines.size
end

#lineString?

Returns The current line content or nil if out of bounds.

Returns:

  • (String, nil)

    The current line content or nil if out of bounds



154
155
156
157
# File 'lib/tins/lines_file.rb', line 154

def line
  index = line_number - 1
  @lines[index] if index >= 0
end

#match_backward(regexp, previous_after_match = false) ⇒ Array<String>?

Match a regular expression backward from current position.

Parameters:

  • regexp (Regexp)

    The regular expression to match

  • previous_after_match (Boolean) (defaults to: false)

    Whether to move back one line after match

Returns:

  • (Array<String>, nil)

    Captured groups or nil if no match



169
170
171
172
173
174
175
176
# File 'lib/tins/lines_file.rb', line 169

def match_backward(regexp, previous_after_match = false)
  begin
    if line =~ regexp
      previous_after_match and previous!
      return $~.captures
    end
  end while previous!
end

#match_forward(regexp, next_after_match = false) ⇒ Array<String>?

Match a regular expression forward from current position.

Parameters:

  • regexp (Regexp)

    The regular expression to match

  • next_after_match (Boolean) (defaults to: false)

    Whether to move forward one line after match

Returns:

  • (Array<String>, nil)

    Captured groups or nil if no match



183
184
185
186
187
188
189
190
# File 'lib/tins/lines_file.rb', line 183

def match_forward(regexp, next_after_match = false)
  begin
    if line =~ regexp
      next_after_match and next!
      return $~.captures
    end
  end while next!
end

#next!LinesFile?

Move to the next line.

Returns:

  • (LinesFile, nil)

    Returns self if successful, nil if at end of file



99
100
101
102
103
# File 'lib/tins/lines_file.rb', line 99

def next!
  old = line_number
  self.line_number += 1
  line_number > old ? self : nil
end

#previous!LinesFile?

Move to the previous line.

Returns:

  • (LinesFile, nil)

    Returns self if successful, nil if at beginning



108
109
110
111
112
# File 'lib/tins/lines_file.rb', line 108

def previous!
  old = line_number
  self.line_number -= 1
  line_number < old ? self : nil
end

#rewindLinesFile

Reset the current line number to the beginning.

Returns:



91
92
93
94
# File 'lib/tins/lines_file.rb', line 91

def rewind
  self.line_number = 1
  self
end

#to_sString

Returns String representation including line number and content.

Returns:

  • (String)

    String representation including line number and content



193
194
195
# File 'lib/tins/lines_file.rb', line 193

def to_s
  "#{line_number} #{line.chomp}"
end