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.
Files changed (3) hide show
  1. checksums.yaml +7 -0
  2. data/lib/paralines.rb +158 -0
  3. 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: []