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: []
         |