-
Notifications
You must be signed in to change notification settings - Fork 0
/
ARGFy.rb
165 lines (140 loc) · 3.56 KB
/
ARGFy.rb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
#
# = ARGFy - a more flexible ARGF
#
# This class is a more flexible version of the ARGF global.
# The constructor takes an array, a list of files, and processes
# them like one constant stream of input. Reading from the
# stream is always line by line either all at once using #each
# or one at a time using #gets.
#
#
# == Attributes
#
# Internal states can help your program understand what
# was processed when you pull any line:
#
# * _lineno_ - line number of the entire stream
# * _filelineno_ - line number of the current file
# * _filename_ - current file being processed
#
#
# == Example
#
# This is a simple program that prints out each file with
# a simple header when the input files change. It shows
# the main advantage of this class over ARGF.
#
# require 'ARGFy'
#
# argf = ARGFy.new(ARGV)
# argf.each do |line|
#
# # Per File Header
# if argf.new_file?
# filename = argf.filename
# filename = "STDIN" if filename == "-"
# puts '', filename, "-"*filename.length
# end
#
# # Print out the line with line numbers
# puts "%3d: %s" % [argf.filelineno, line]
#
# end
#
#
# == Contact
#
# Author:: Joseph Pecoraro (mailto:[email protected])
# Copyright:: Copyright (c) 2008 Joseph Pecoraro
# License:: Distributes under the same terms as Ruby
#
class ARGFy
# its enumerable, line by line
include Enumerable
# last line number read from the entire stream
attr_accessor :lineno
# last line number read from the current file
attr_accessor :filelineno
# filename of the current file being read
attr_accessor :filename
# Constructor takes an optional list of files, and will default
# to just using STDIN on an empty list.
def initialize(file_arr=[])
@files = ["-"]
@files = file_arr unless file_arr.empty?
reset
end
# Sets the public and private states to their default values
def reset
@lineno = 0
@filelineno = 0
@filename = @files.first
@index = 0
@lines = nil
end
# Add a file to the file list
def add_file(str)
@files.push(str)
end
# Goes through the lines of all files constantly updating
# the internal states _filename_, _lineno_, and _filelineno_.
def each
# Save States that this affects, and set them to defaults
states = [@lineno, @filelineno, @filename]
@lineno = 0;
# Read every line walking through the files
@files.each do |filename|
# Setup States Per File
@filename = filename
@filelineno = 0
stream = STDIN
stream = File.open(filename) unless filename == '-'
# Read Lines
while line = stream.gets
@lineno += 1
@filelineno += 1
yield line
end
end
# Restore the original states
@lineno, @filelineno, @filename = states
end
# Gets each line individually.
def gets
# Quick exit when depleted
return nil if @index >= @files.size
@filename = @files[@index]
# Special case for STDIN
# Handle a STDIN break right here
if @filename == "-"
line = STDIN.gets
if line.nil?
@index += 1
@filelineno = 0
return gets
else
@lineno += 1
@filelineno += 1
return line
end
end
# Bulk read into @lines
@lines = File.open(@filename).readlines if @lines.nil?
# When Depleted, go to the next
if @filelineno >= @lines.size
@index += 1
@filelineno = 0
@lines = nil
return gets
end
# Reads the line, updates internal variables
line = @lines[@filelineno]
@lineno += 1
@filelineno += 1
return line
end
# Returns true if the last line read was from a new file
def new_file?
@filelineno == 1
end
end