paralines 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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: []
|