paralines 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/lib/paralines.rb +158 -0
- metadata +58 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 529c8563443dc4d0433a4e969ad894b76ded11e579a8f1781d859bd004e83464
|
4
|
+
data.tar.gz: 4f96bf28dfcc1726a27fe770f558b82b1ae7d77f4216abf818df34c970043fc0
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 849db8748f0ffac034e984a3083ff6feab2e238a01b23b8c8ce77059ae804349413870444077d374eab0570e261fcb855b425dd7e94905ff289a9d72affd9527
|
7
|
+
data.tar.gz: 87cc010c941f8a029ed86f5a8b1945e5ce37cfbb0661cb90052874b74cb81e023ea68eab46ed2ccd4db06e81100c58f03b135ec6b1c0f8d169a3401eaf916f6c
|
data/lib/paralines.rb
ADDED
@@ -0,0 +1,158 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
class ParaLines
|
4
|
+
C_mutex = Mutex.new
|
5
|
+
def C_mutex.sync_if_needed
|
6
|
+
if owned?
|
7
|
+
yield
|
8
|
+
else
|
9
|
+
synchronize do
|
10
|
+
yield
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
def initialize
|
16
|
+
set_flags!
|
17
|
+
@line_by_key = Hash.new {|h, key| h[key] = {line:h.length, col:1, text:''} }
|
18
|
+
|
19
|
+
# *ensure flush at exit
|
20
|
+
if @f_to_file
|
21
|
+
at_exit do
|
22
|
+
flush
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
if block_given?
|
27
|
+
begin
|
28
|
+
yield self
|
29
|
+
ensure
|
30
|
+
flush
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
# plines << "done (#{n})"
|
36
|
+
def << (text)
|
37
|
+
key = Thread.current
|
38
|
+
output key, text
|
39
|
+
end
|
40
|
+
|
41
|
+
# plines.add_static_line '- 5 workers added'
|
42
|
+
def add_static_line(text)
|
43
|
+
key = text.object_id
|
44
|
+
C_mutex.synchronize do
|
45
|
+
d = @line_by_key[key]
|
46
|
+
if @f_to_console
|
47
|
+
puts text
|
48
|
+
else # for file
|
49
|
+
d[:text] += text.to_s
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
# done_order_line = plines.add_shared_line 'Done order: '
|
55
|
+
# done_order_line << 'some text'
|
56
|
+
# part = shared_line.part_open "#{n}… " + later: part.close '+'
|
57
|
+
# *can output part progress by adding dots: [LS ] [cloud2… ] --> [LS....] [cloud2… ] — call .close('.' * done_count) multiple times with increasing number of dots
|
58
|
+
# *this line can be used by many threads
|
59
|
+
def add_shared_line(text)
|
60
|
+
key = text.object_id
|
61
|
+
output key, text
|
62
|
+
# < helper obj with the << and .part_open methods
|
63
|
+
Object.new.tap do |o|
|
64
|
+
rel = self
|
65
|
+
line_by_key = @line_by_key
|
66
|
+
f_to_console = @f_to_console
|
67
|
+
|
68
|
+
o.define_singleton_method :<< do |text|
|
69
|
+
rel.send :output, key, text
|
70
|
+
end
|
71
|
+
|
72
|
+
o.define_singleton_method :part_open do |text_|
|
73
|
+
d = line_by_key[key]
|
74
|
+
part_col = nil
|
75
|
+
|
76
|
+
C_mutex.synchronize do
|
77
|
+
# *we replace placeholder chars like: … or _ or just the last char (order here needed for priority to be able to have _ in text and use … as a placeholder)
|
78
|
+
part_col = d[:col] + (text_.index('…') || text_.index('_') || text_.length-1)
|
79
|
+
|
80
|
+
rel.send :output, key, text_
|
81
|
+
end
|
82
|
+
|
83
|
+
# < helper obj with the .close method
|
84
|
+
Object.new.tap do |o|
|
85
|
+
o.define_singleton_method :close do |end_text|
|
86
|
+
# *print the closing chars in the saved position
|
87
|
+
if f_to_console
|
88
|
+
rel.send :print_in_line,
|
89
|
+
lines_up: line_by_key.count - d[:line],
|
90
|
+
col: part_col,
|
91
|
+
text: end_text
|
92
|
+
else # for file
|
93
|
+
d[:text][part_col-1, end_text.length] = end_text
|
94
|
+
end
|
95
|
+
end
|
96
|
+
end
|
97
|
+
end
|
98
|
+
end
|
99
|
+
end
|
100
|
+
|
101
|
+
# plines.flush
|
102
|
+
# *needed only when @f_to_file
|
103
|
+
# *can be called manually if the block form was not used and all the threads are finished
|
104
|
+
def flush
|
105
|
+
puts @line_by_key.map {|key, d| d[:text] } if @f_to_file
|
106
|
+
@line_by_key.clear
|
107
|
+
end
|
108
|
+
|
109
|
+
|
110
|
+
# *needed for rewriting in tests
|
111
|
+
private \
|
112
|
+
def set_flags!
|
113
|
+
@f_to_console = $>.tty?
|
114
|
+
@f_to_file = !$>.tty?
|
115
|
+
end
|
116
|
+
|
117
|
+
|
118
|
+
private \
|
119
|
+
def output(key, text)
|
120
|
+
text = text.to_s
|
121
|
+
C_mutex.sync_if_needed do
|
122
|
+
|
123
|
+
# add line
|
124
|
+
puts if @f_to_console && !@line_by_key.has_key?(key)
|
125
|
+
|
126
|
+
d = @line_by_key[key]
|
127
|
+
|
128
|
+
if @f_to_console
|
129
|
+
print_in_line(
|
130
|
+
lines_up: @line_by_key.count - d[:line],
|
131
|
+
col: d[:col],
|
132
|
+
text: text
|
133
|
+
)
|
134
|
+
else # for file
|
135
|
+
d[:text] += text
|
136
|
+
end
|
137
|
+
|
138
|
+
d[:col] += text.length
|
139
|
+
end
|
140
|
+
end
|
141
|
+
|
142
|
+
|
143
|
+
private \
|
144
|
+
def print_in_line(lines_up:, col:, text:)
|
145
|
+
# \e[s — save cursor position
|
146
|
+
# \e[nA — move n lines up
|
147
|
+
# \e[nG — move to n-th column
|
148
|
+
# \e[u — restore cursor position
|
149
|
+
print <<~OUT.delete("\n")
|
150
|
+
\e[s
|
151
|
+
\e[#{lines_up}A
|
152
|
+
\e[#{col}G
|
153
|
+
#{text}
|
154
|
+
\e[u
|
155
|
+
OUT
|
156
|
+
end
|
157
|
+
|
158
|
+
end
|
metadata
ADDED
@@ -0,0 +1,58 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: paralines
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 1.0.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Yura Babak
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2022-01-27 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: rspec
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '3.5'
|
20
|
+
type: :development
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - "~>"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '3.5'
|
27
|
+
description:
|
28
|
+
email:
|
29
|
+
- yura.des@gmail.com
|
30
|
+
executables: []
|
31
|
+
extensions: []
|
32
|
+
extra_rdoc_files: []
|
33
|
+
files:
|
34
|
+
- lib/paralines.rb
|
35
|
+
homepage: https://github.com/Inversion-des/paralines
|
36
|
+
licenses:
|
37
|
+
- MIT
|
38
|
+
metadata: {}
|
39
|
+
post_install_message:
|
40
|
+
rdoc_options: []
|
41
|
+
require_paths:
|
42
|
+
- lib
|
43
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - ">="
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '0'
|
48
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
49
|
+
requirements:
|
50
|
+
- - ">="
|
51
|
+
- !ruby/object:Gem::Version
|
52
|
+
version: '0'
|
53
|
+
requirements: []
|
54
|
+
rubygems_version: 3.2.22
|
55
|
+
signing_key:
|
56
|
+
specification_version: 4
|
57
|
+
summary: Nice output to console/file from concurrent threads.
|
58
|
+
test_files: []
|