cremefraiche 1.1.8

Sign up to get free protection for your applications and to get access to all the features.
Files changed (58) hide show
  1. checksums.yaml +7 -0
  2. data/README.md +114 -0
  3. data/bin/cremefraiche +117 -0
  4. data/bin/cremefraicheGui +26 -0
  5. data/cremefraiche.gemspec +24 -0
  6. data/doc/gui_howto.pdf +0 -0
  7. data/lib/LANG +1 -0
  8. data/lib/basic_logging.rb +170 -0
  9. data/lib/busy_indicator/.busy_function_test.rb.swp +0 -0
  10. data/lib/busy_indicator/.busy_indicator.rb.swp +0 -0
  11. data/lib/busy_indicator/.color_output.rb.swp +0 -0
  12. data/lib/busy_indicator/busy_function_test.rb +50 -0
  13. data/lib/busy_indicator/busy_indicator.rb +89 -0
  14. data/lib/busy_indicator/color_output.rb +45 -0
  15. data/lib/cfprawn.rb +387 -0
  16. data/lib/confcheck.rb +103 -0
  17. data/lib/config +187 -0
  18. data/lib/configuration.rb +234 -0
  19. data/lib/configuration.rb~ +247 -0
  20. data/lib/cremefraiche.rb +181 -0
  21. data/lib/emlfile.rb +136 -0
  22. data/lib/file_checking.rb +82 -0
  23. data/lib/gui/.ButtonLabel.rb.swp +0 -0
  24. data/lib/gui/.conf_value.rb.swp +0 -0
  25. data/lib/gui/.cremefraicheGui.rb.swp +0 -0
  26. data/lib/gui/.message_dialog.rb.swp +0 -0
  27. data/lib/gui/AboutDialog.rb +63 -0
  28. data/lib/gui/ButtonLabel.rb +41 -0
  29. data/lib/gui/ConfDialog.rb +610 -0
  30. data/lib/gui/HowtoDialog.rb +183 -0
  31. data/lib/gui/conf_option.rb +274 -0
  32. data/lib/gui/conf_value.rb +58 -0
  33. data/lib/gui/cremefraicheGui.rb +568 -0
  34. data/lib/gui/gtk-about.xpm +90 -0
  35. data/lib/gui/gtk-close.xpm +90 -0
  36. data/lib/gui/gtk-execute.xpm +118 -0
  37. data/lib/gui/gtk-open.xpm +147 -0
  38. data/lib/gui/gtk-properties.xpm +378 -0
  39. data/lib/gui/gtk-quit.xpm +352 -0
  40. data/lib/gui/gtk-remove.xpm +123 -0
  41. data/lib/gui/gtk-save.xpm +214 -0
  42. data/lib/gui/gtk-stop.xpm +344 -0
  43. data/lib/gui/help.xpm +463 -0
  44. data/lib/gui/icon.xpm +300 -0
  45. data/lib/gui/message_dialog.rb +34 -0
  46. data/lib/gui/okay.xpm +49 -0
  47. data/lib/gui/preferences-color.xpm +252 -0
  48. data/lib/gui/view.xpm +75 -0
  49. data/lib/html2text.rb +195 -0
  50. data/lib/icon/icon.xpm +300 -0
  51. data/lib/icon/icon_big.xpm +661 -0
  52. data/lib/license.rb +38 -0
  53. data/lib/log.conf +65 -0
  54. data/lib/tag_munging.rb +89 -0
  55. data/lib/translating.rb +78 -0
  56. data/lib/translations +609 -0
  57. data/lib/version.rb +25 -0
  58. metadata +221 -0
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 48cc0065d28074c113f879f7dbc47e424b78a52e75f54eeb74f25d287658e8c6
4
+ data.tar.gz: 16b22c86a2c3843de9a3000c336108196bb2deb480eaff8761f8d22b2cb07075
5
+ SHA512:
6
+ metadata.gz: 6a668022a9d83c0977c6f53fd0b8ab19cb9ebfb5b74ddc8d3203862ce7daf369a28b7abc55259dcde290f7224cbba4f1edc1ce4a4b6d8ff4680aee646d824830
7
+ data.tar.gz: ee181963d9fbf566b13a40777c78295d01503d449145746a64a76bdb10d1050e96d2d4e39ba0db8622b4c54a97a1c6b969c03491d005d5829f14b69790406b8a
data/README.md ADDED
@@ -0,0 +1,114 @@
1
+ Creme Fraîche
2
+ =======================
3
+ Email to PDF Konverter
4
+ ------------------------------------------
5
+
6
+ SYNOPSIS
7
+ =======================
8
+
9
+ **cremefraiche [eml-files] ...**
10
+
11
+ **cremefraiche < mail**
12
+
13
+ **cremefraicheGui**
14
+
15
+
16
+
17
+ DESCRIPTION
18
+ =======================
19
+ This program converts email to PDF. The objective is to keep readable
20
+ versions of the messages, HTML versions of the processed mails are simplified,
21
+ colors and images are lost in the process.
22
+
23
+ The resulting mails will be created either
24
+
25
+ * in the same directory alongside the original eml files
26
+
27
+ * when 1 mail is piped-in to cremefraiche, in the *current working directory*.
28
+ In this case, the new PDF-file will overwrite, if it exists, an existing file
29
+ *001_mail_message.pdf*
30
+
31
+ **ATTN!** Not all html flavors will result in usable PDF; reacting to all
32
+ possible variations in the way that Mail is created these days, is an ongoing
33
+ endeavor. If you need authentic output of a HTML mail, **use a different
34
+ software**, a Web Browser or a converter specifically developed for the task.
35
+
36
+ CONFIGURATION
37
+ ===============
38
+ Cremefraiche is highly configurable.
39
+
40
+ To create your own version of the configuration file in order to modify
41
+ the behavior of the program, execute cremefraiche once with the only
42
+ argument “user-conf”:
43
+
44
+ **user@machine:~$ cremefraiche user-conf**
45
+
46
+ The file will be written in a hidden subdirectory *.cremefraiche* and is
47
+ named *config*. It is full of explanations and it should be no problem to do the
48
+ necessary adaptations directly in the file.
49
+
50
+ You can also set and modify values in the GUI, after pushing the button
51
+ that refers to the configuration.
52
+
53
+ The Graphical User Interface
54
+ ============================
55
+ Execute
56
+
57
+ **cremefraicheGui**.
58
+
59
+ The simplistic GUI serves to keep a list of eml files for repeated conversion
60
+ to PDF. You can also exempt files from this list from an immediate conversion
61
+ but keep it for later use.
62
+
63
+ In the GUI, you can also decide to interrupt running conversions in a
64
+ way that necessitates a kill-signal in the console version of the program.
65
+
66
+ Other Information
67
+ =================
68
+
69
+ pipe-in a mail from STDIN
70
+ --------------------------
71
+ You can pipe in mails to cremefraiche. This is useful for use in conjunction
72
+ with mail-clients that allow such operation, notably the *Mutt* mail client.
73
+ For Mutt, it is sufficient to define two macros in the file .muttrc :
74
+
75
+ <code>macro index X "|cremefraiche -\n" "make PDF"</code>
76
+
77
+ <code>macro pager X "|cremefraiche -\n" "make PDF"</code>
78
+
79
+ This will enable the Shortcut *Shift-x* in the mail index and in the pager.
80
+
81
+ Source-Code
82
+ -----------
83
+ The gem-file that you get with the gem-utility or from rubygems.org contains
84
+ all the code of the program and some documentation (this page notably). To read
85
+ its content, you must
86
+
87
+ 1. untar the gem-file with tar _-xf cremefraiche-1.1.7.gem_
88
+ 2. uncompress the data.gz archive: _gunzip data.gz_
89
+ 3. untar the resultig data.tar archive: _tar -xf data.tar_
90
+
91
+ This creates the directories bin, doc and lib.
92
+
93
+ Why « Crème Fraîche » ?
94
+ -----------------------
95
+ As with *Crème Fraîche* you create splendid meals from otherwise frugal
96
+ ingredients, I found it a good name for the initial versions of the program.
97
+
98
+ In the meantime – and under the influence of too much HTML garbage – I wonder
99
+ what you will make of it. Though simplifying the HTML-mail that I receive, in
100
+ an effort to make it readable, is still an objective.
101
+
102
+ License
103
+ -------
104
+ **Cremefraiche** is distributed under the conditions of the WTFPL-2.0 or later
105
+ License (see http://www.wtfpl.net/txt/copying/ or license-text in the doc
106
+ directory of the gem-file).
107
+
108
+ Author
109
+ -----
110
+ Cremefraiche has been developed by
111
+ Michael Uplawski <michael.uplawski@uplawski.eu>
112
+
113
+ Ω
114
+ ==
data/bin/cremefraiche ADDED
@@ -0,0 +1,117 @@
1
+ #!/usr/bin/env ruby
2
+ #encoding: UTF-8
3
+ =begin
4
+ /***************************************************************************
5
+ * ©2011-2023, Michael Uplawski <michael.uplawski@uplawski.eu> *
6
+ * *
7
+ * This program is free software; you can redistribute it and/or modify *
8
+ * it under the terms of the WTFPL 2.0 or later version of the LICENSE. *
9
+ * See https://wtfpl2.com/ for details. *
10
+ * *
11
+ * This program is distributed in the hope that it will be useful, *
12
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of *
13
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. *
14
+ * *
15
+ ***************************************************************************/
16
+ =end
17
+
18
+ $WIN = (RUBY_PLATFORM =~ /mswin/)
19
+
20
+ require_relative '../lib/translating'
21
+ require_relative '../lib/basic_logging'
22
+ require_relative '../lib/cremefraiche'
23
+ require_relative '../lib/confcheck'
24
+ require_relative '../lib/version'
25
+
26
+ extend(BasicLogging)
27
+ extend(Translating)
28
+
29
+ # prints the usage message
30
+ def usage
31
+ if $WIN
32
+ system 'cls'
33
+ else
34
+ system( 'clear')
35
+ end
36
+ prog_version = (App_name.dup << ' ' << trl("version %s") %[VERSION])
37
+ sub_title = trl('EML to PDF converter')
38
+ width = 32 + [prog_version, sub_title].max {|a, b| a.length <=>b.length}.length
39
+ hr = '━' * width
40
+
41
+ ustr = []
42
+ ustr << " ┏%s┓" %hr
43
+ ustr << " ┃%#{width - 16}s ┃" %prog_version
44
+ ustr << " ┃%#{width - 16}s ┃" %sub_title
45
+ ustr << " ┗%s┛" %hr
46
+ ustr << ''
47
+ ustr << " © %s %s %s" %[YEARS, Author, Author_mail]
48
+ ustr << ''
49
+ ustr << " %s" %(trl("Running with Ruby %s on %s") %[RUBY_VERSION, RUBY_PLATFORM])
50
+ ustr << ''
51
+ u = trl("Usage")
52
+ ulen = u.length + 1;
53
+ ustr << " %s:" %u
54
+ ustr << ('▔' * ulen )
55
+ ustr << " \tuser@machine:~$ cremefraiche [%s.eml] <%s.eml ... %s(n).eml>" %[trl('eml_file1'), trl('eml_file2'), trl('eml_file')]
56
+ ustr << ''
57
+ ustr << " %s" %trl('This produces 1 PDF-file for each individual email found in the given eml-file(s).')
58
+ ustr << " %s:" %trl("Please see the file 'config' in the program- or gem-folder for some options")
59
+ ustr << " \t%s" %[$CONF.config_file]
60
+ ustr << ''
61
+ ustr << " %s:" %trl("To create or update a user-version of the configuration-file")
62
+ ustr << ('▔' * ulen )
63
+ ustr << " \tuser@machine:~$ ruby cremefraiche user-conf"
64
+ ustr << ''
65
+ ustr << " %s %s" %[trl("Use literally 'user-conf' as argument."), trl("This either creates or overwrites\n a configuration file in a sub-directory '.cremefraiche' of the current user's home-directory")]
66
+ ustr << "\n"
67
+ ustr << "This program is free software under the terms of the WTFPL version 2 or later. "
68
+ ustr << "It is provided as is with no guarantees of any kind."
69
+ ustr << "\n" * 2
70
+ ustr.join("\n")
71
+ end
72
+
73
+
74
+
75
+ if(ARGV && ARGV.flatten.empty? )
76
+ debug('printing usage-message')
77
+ puts usage()
78
+ elsif ARGV[0] && 'user-conf' == ARGV[0].chomp
79
+ debug('handling user-configuration')
80
+ handle_user_conf
81
+ end
82
+
83
+
84
+ cf = CremeFraiche.instance()
85
+ cf.process(*ARGV)
86
+
87
+ # Should a user wish to either update her/his private version of the configuration-file by the current
88
+ # contents of the file originally found in the downloaded program package, this function does the job.
89
+ # It creates a copy of the original file, also, if there is not yet one, in ~/.cremefraiche/config or
90
+ # whatever the Configuration-singleton returns as file-name for user_configuration.
91
+ def handle_user_conf
92
+ conf_check = ConfCheck.new()
93
+ diffs = conf_check.diffs
94
+ replace = false
95
+ if( diffs)
96
+ if(diffs && diffs[:missing].empty? && diffs[:additional].empty?)
97
+ puts trl("No changes to your user-configuration are necessary.")
98
+ return false;
99
+ else
100
+ m = diffs[:missing]
101
+ a = diffs[:additional]
102
+ puts trl("\nThe following changes can be effectuated on your user-configuration")
103
+ puts "\t+ " << trl("New options") << ":\n\t\t" << m.join('\n\t\t ') if !m.empty?
104
+ puts "\t- " << trl("Obsolete Options") << ":\n\t\t" << a.join(', ') if !a.empty?
105
+ puts trl("Do you want to replace your current user-configuration?")
106
+ puts trl("If you answer 'yes' a back-up copy of your old file will still be available.")
107
+ puts trl("But your old settings will be replaced by the defaults.")
108
+ print trl("Your answer (Y/n): ")
109
+ replace = STDIN.getc.downcase == trl("y") ? true : false
110
+ end
111
+ if(! replace)
112
+ return false;
113
+ end
114
+ end
115
+ conf_check.write_user_conf
116
+ return replace;
117
+ end
@@ -0,0 +1,26 @@
1
+ #!/usr/bin/env ruby
2
+ #encoding: UTF-8
3
+ =begin
4
+ /***************************************************************************
5
+ * ©2011-2013, Michael Uplawski <michael.uplawski@uplawski.eu> *
6
+ * *
7
+ * This program is free software; you can redistribute it and/or modify *
8
+ * it under the terms of the GNU General Public License as published by *
9
+ * the Free Software Foundation; either version 3 of the License, or *
10
+ * (at your option) any later version. *
11
+ * *
12
+ * This program is distributed in the hope that it will be useful, *
13
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of *
14
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
15
+ * GNU General Public License for more details. *
16
+ * *
17
+ * You should have received a copy of the GNU General Public License *
18
+ * along with this program; if not, write to the *
19
+ * Free Software Foundation, Inc., *
20
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
21
+ ***************************************************************************/
22
+
23
+
24
+ =end
25
+ require_relative '../lib/gui/cremefraicheGui'
26
+ CremeFraicheGui.new(ARGV)
@@ -0,0 +1,24 @@
1
+ require_relative "lib/version"
2
+ require 'date'
3
+
4
+ Gem::Specification.new do |s|
5
+ s.version = VERSION
6
+ s.name = File.basename(__FILE__, '.gemspec')
7
+ s.date = Date.today.strftime('%F')
8
+ s.summary = SUMMARY
9
+ s.description = "transforms EML files to PDF"
10
+ s.authors = Author
11
+ s.email = Author_mail
12
+ s.files = Dir.children('doc').collect{|f| 'doc/' << File::path(f)} + Dir.children('bin').collect{|f| 'bin/' << File::path(f)} + Dir.children('lib').collect{|f| 'lib/' << File::path(f) } + Dir.children('lib/gui/').collect{|f| 'lib/gui/' << File::path(f) } + Dir.children('lib/icon').collect{|f| 'lib/icon/' << File::path(f) } + Dir.children('lib/busy_indicator').collect{|f| 'lib/busy_indicator/' << File::path(f) } + %w~cremefraiche.gemspec~.collect{|f|f} << "README.md"
13
+ s.homepage = ''
14
+ s.requirements = 'prawn prawn-table escape nokogiri mail gtk3'
15
+ s.add_runtime_dependency 'prawn', '~> 2.4', '>= 2.4.0'
16
+ s.add_runtime_dependency 'prawn-table', '~> 0.2', '>= 0.2.2'
17
+ s.add_runtime_dependency 'escape', '~> 0.0', '>= 0.0.4'
18
+ s.add_runtime_dependency 'nokogiri', '~> 1.13', '>= 1.13.10'
19
+ s.add_runtime_dependency 'mail', '~> 2.8', '>= 2.8.0'
20
+ s.add_runtime_dependency 'gtk3', '~> 4.0', '>= 4.0.5'
21
+ s.executables = 'cremefraiche', 'cremefraicheGui'
22
+ s.license = 'GPL-3.0'
23
+ s.required_ruby_version = '>= 2.5'
24
+ end
data/doc/gui_howto.pdf ADDED
Binary file
data/lib/LANG ADDED
@@ -0,0 +1 @@
1
+ en
@@ -0,0 +1,170 @@
1
+ #!/bin/env ruby
2
+ #encoding: UTF-8
3
+ =begin
4
+ /***************************************************************************
5
+ * ©2013-2023, Michael Uplawski <michael.uplawski@uplawski.eu> *
6
+ * *
7
+ * This program is free software; you can redistribute it and/or modify *
8
+ * it under the terms of the WTFPL 2.0 or later, see *
9
+ * http://www.wtfpl.net/about/ *
10
+ * *
11
+ * This program is distributed in the hope that it will be useful, *
12
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of *
13
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. *
14
+ * *
15
+ ***************************************************************************/
16
+ =end
17
+
18
+ #
19
+ # Simplified logging.
20
+ # See example code at the bottom of this file.
21
+ # Execute this file to see the output.
22
+ #
23
+
24
+ #require 'time'
25
+
26
+ module BasicLogging
27
+
28
+ DEBUG = 0
29
+ INFO = 1
30
+ WARN = 2
31
+ ERROR = 3
32
+ FATAL = 4
33
+ UNKNOWN = nil
34
+
35
+ # this is mainly for the translation of method calls into log levels
36
+ Levels = {:debug => DEBUG, :info => INFO, :warn => WARN, :error => ERROR,
37
+ :fatal => FATAL, :unknown => UNKNOWN}
38
+
39
+ @@log_level = UNKNOWN
40
+ @@target = STDOUT
41
+ @@muted = []
42
+
43
+ # do not log, if caller is name (class or instance)
44
+ def self.mute(obj)
45
+ name = obj.class == Class ? obj.name.dup : obj.class.name
46
+ @@muted << name
47
+ end
48
+
49
+ def self.is_muted?(obj)
50
+ name = obj.class == Class ? obj.name.dup : obj.class.name
51
+ @@muted.include?(name)
52
+ end
53
+
54
+ # set the log level for the calling class or object
55
+ def set_level(lv)
56
+ if lv.respond_to?(:to_str)
57
+ lv = Levels[lv.to_sym]
58
+ end
59
+ if(!lv || (lv.respond_to?(:to_int) && lv >= DEBUG && lv <= FATAL) )
60
+ @@log_level = lv
61
+ else
62
+ STDERR.puts __FILE__.dup << ": ERROR : invalid log level \"" << lv.to_s << "\""
63
+ STDERR.puts "Keepinng old log level " << Levels.keys.detect {| k| Levels[k] == @@log_level}.to_s
64
+ end
65
+ end
66
+
67
+ # set the log target for the calling class or object
68
+ def set_target(tg)
69
+ if tg.respond_to?(:to_io)
70
+ @@target = tg
71
+ elsif(!File::exist?(tg) || ( File.file?(tg) && File.writable?(tg) ) )
72
+ @@target = File.open(tg, 'w+')
73
+ else
74
+ STDERR.puts __FILE__.dup << ': ERROR : target ' << tg << ' cannot be set'
75
+ STDERR.puts "Keeping old target " << @@target.inspect
76
+ return
77
+ end
78
+ end
79
+
80
+ # Output of log messages, depending on the log level set for the calling class
81
+ # and the name of the alias method which is actually called.
82
+ def log(message)
83
+ if !BasicLogging.is_muted?(self)
84
+ # how has this method been called?
85
+ mlevel = __callee__
86
+ if Levels.has_key?(mlevel) && Levels[mlevel] <= FATAL
87
+ # output only for levels equal or above the value that corresponds to
88
+ # the calling alias.
89
+ format_log( message, mlevel) if @@log_level && Levels[mlevel] >= @@log_level
90
+ else
91
+ STDERR.puts __FILE__.dup << ": ERROR : invalid log level \"" << mlevel.to_s << "\""
92
+ end
93
+ end
94
+ end
95
+
96
+ alias :debug :log
97
+ alias :info :log
98
+ alias :warn :log
99
+ alias :error :log
100
+ alias :fatal :log
101
+
102
+ attr_reader :target, :log_level
103
+
104
+ private
105
+
106
+ # 1 format_log for all loggers.
107
+ def format_log(message, mlevel)
108
+ # indicate if a registered class or the registered object of a class is calling.
109
+ name = self.class == Class ? self.name.dup << ' [class]' : self.class.name
110
+ @@target.puts '' << name << ' ' << mlevel.to_s << ' ' << Time.now.strftime("%H:%M:%S:%6N") << ': ' << message
111
+ end
112
+ end
113
+ #---------test: execute file----------
114
+ if $0 == __FILE__
115
+ Array.extend(BasicLogging)
116
+ Array.set_level(BasicLogging::INFO)
117
+ Array.info('TEST')
118
+ ar = Array.new
119
+ ar.extend(BasicLogging)
120
+ # --- no output :
121
+ l = __LINE__
122
+ ar.debug(l.next.to_s << ': debug-test 0')
123
+ # output
124
+ ar.set_level(BasicLogging::DEBUG)
125
+ l = __LINE__
126
+ ar.debug(l.next.to_s << ': debug-test 1')
127
+
128
+ obj = Object.new
129
+ obj.extend(BasicLogging)
130
+ obj.set_level(BasicLogging::DEBUG)
131
+ puts "--------debug-----------"
132
+ obj.debug('debug')
133
+ obj.info('info')
134
+ obj.warn('warn')
135
+ obj.error('error')
136
+ obj.fatal('fatal')
137
+ puts "--------info-----------"
138
+ obj.set_level("info")
139
+ obj.debug('debug')
140
+ obj.info('info')
141
+ obj.warn('warn')
142
+ obj.error('error')
143
+ obj.fatal('fatal')
144
+ puts "--------fatal-----------"
145
+ obj.set_level("fatal")
146
+ obj.debug('debug')
147
+ obj.info('info')
148
+ obj.warn('warn')
149
+ obj.error('error')
150
+ obj.fatal('fatal')
151
+ puts "--------UNKNOWN-----------"
152
+ obj.set_level(nil)
153
+ obj.debug('debug')
154
+ obj.info('info')
155
+ obj.warn('warn')
156
+ obj.error('error')
157
+ obj.fatal('fatal')
158
+ puts " ------ Output into file ----"
159
+ obj.set_target "/tmp/test_log.log"
160
+ puts " ------ INFO -----------"
161
+ obj.set_level BasicLogging::INFO
162
+ obj.info('info output')
163
+
164
+ obj.info('info output 2')
165
+ puts "---------- invalid -------"
166
+ obj.set_target "/dev/sr0"
167
+ obj.set_level "power"
168
+ end
169
+
170
+ # EOF
@@ -0,0 +1,50 @@
1
+ #encoding: UTF-8
2
+ =begin
3
+ /***************************************************************************
4
+ * ©2011-2023, Michael Uplawski <michael.uplawski@uplawski.eu> *
5
+ * *
6
+ * This program is free software; you can redistribute it and/or modify *
7
+ * it under the terms of the WTFPL 2.0 or later version of the LICENSE. *
8
+ * See https://wtfpl2.com/ for details. *
9
+ * *
10
+ * This program is distributed in the hope that it will be useful, *
11
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of *
12
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. *
13
+ * *
14
+ ***************************************************************************/
15
+
16
+ A test and demo for the BusyIndicator.
17
+ This does not use the final BusyIndicator but directly creates
18
+ a Thread.
19
+ =end
20
+ require './color_output'
21
+
22
+ def clean_busy_indicator(thr, width, comment)
23
+ thr.terminate
24
+ thr.join
25
+ print ("\b" * width)
26
+ print ("%+#{width}s\n" %comment)
27
+ end
28
+
29
+ def busy_indicator(width)
30
+ tobj = Thread.new() do
31
+ loop do
32
+ %w"OOO ooo ___ ooo".each do |s|
33
+ print "%+#{width}s" %s
34
+ sleep 0.1
35
+ print ("\b" * width)
36
+ end
37
+ end
38
+ end
39
+ end
40
+ # =======================
41
+ if($0 == __FILE__)
42
+ width = 20
43
+ 2.times do
44
+ puts "I am busy, pse wait..."
45
+ thr = busy_indicator(width)
46
+ sleep 3
47
+ clean_busy_indicator(thr, width, "Okay")
48
+ end
49
+ end
50
+
@@ -0,0 +1,89 @@
1
+ #encoding: UTF-8
2
+ =begin
3
+ /***************************************************************************
4
+ * ©2011-2023, Michael Uplawski <michael.uplawski@uplawski.eu> *
5
+ * *
6
+ * This program is free software; you can redistribute it and/or modify *
7
+ * it under the terms of the WTFPL 2.0 or later version of the LICENSE. *
8
+ * See https://wtfpl2.com/ for details. *
9
+ * *
10
+ * This program is distributed in the hope that it will be useful, *
11
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of *
12
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. *
13
+ * *
14
+ ***************************************************************************/
15
+ =end
16
+
17
+ require_relative 'color_output'
18
+
19
+ #The BusyIndicator will show an "Animation" for the time of its execution.
20
+ #The main program will continue to run in its own thread and should stop
21
+ #the BusyIndicator, once that a process of longer duration has terminated.
22
+ class BusyIndicator
23
+ attr_writer :width
24
+ # Defines a busy_indicator of a width of 'width' characters.
25
+ # If 'start' is true, the text-animation is run immediately.
26
+ def initialize(start = true, width = nil)
27
+ @width = width && width >= 3 ? width : 3
28
+ @thr = busy_indicator(@width) if start
29
+ end
30
+
31
+ # Starts the text-animation, returns the thread.
32
+ def run()
33
+ @thr = busy_indicator(@width)
34
+ end
35
+
36
+ # Stops the text-animation, terminates the thread.
37
+ # If comment is not null, it will be displayed in the end.
38
+ def stop(comment)
39
+ @thr.terminate
40
+ @thr.join
41
+ print ("\b" * @width)
42
+ print ("%+#{@width}s\n" %comment)
43
+ end
44
+ private
45
+ def busy_indicator(width)
46
+ tobj = Thread.new() do
47
+ print "working ... "
48
+ loop do
49
+ # %w"OOO ooo ___ ooo".each do |s|
50
+ %w"000 OOO UUU VVV YYY TTT 777 >>> === --- ooo".each do |s|
51
+ # %w"0OU OUV UVY VYT YT7 T7> 7>= >=- =-o -o0 o0O".each do |s|
52
+ print "%+#{width}s" %s
53
+ sleep 0.1
54
+ print ("\b" * width)
55
+ end
56
+ end
57
+ end
58
+ end
59
+ end
60
+ # =======================
61
+ # Example
62
+ # You can run this file directly from a command-line,
63
+ # like this
64
+ # user@mchine$: ruby busy_indicator.rb
65
+ #
66
+ # The program below will then start four (4)
67
+ # BusyIndicators and stop them again, one by one.
68
+ # The width of the "animation" is variated.
69
+ # In the loop, the BusyIndicator is started upon
70
+ # its creation, the other two instances are first
71
+ # created then 'run'.
72
+ if($0 == __FILE__)
73
+ width = 20
74
+ 2.times do
75
+ puts "I am busy, pse wait..."
76
+ thr = BusyIndicator.new(true, width)
77
+ sleep 3
78
+ thr.stop("Okay")
79
+ end
80
+ bi = BusyIndicator.new(false)
81
+ bi.run
82
+ sleep 3
83
+ bi.stop("Stopped")
84
+ bi.width = 8
85
+ bi.run
86
+ sleep 3
87
+ bi.stop("stopped again")
88
+ end
89
+
@@ -0,0 +1,45 @@
1
+ #encoding: UTF-8
2
+ =begin
3
+ /***************************************************************************
4
+ * ©2011-2023, Michael Uplawski <michael.uplawski@uplawski.eu> *
5
+ * *
6
+ * This program is free software; you can redistribute it and/or modify *
7
+ * it under the terms of the WTFPL 2.0 or later version of the LICENSE. *
8
+ * See https://wtfpl2.com/ for details. *
9
+ * *
10
+ * This program is distributed in the hope that it will be useful, *
11
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of *
12
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. *
13
+ * *
14
+ ***************************************************************************/
15
+ =end
16
+
17
+ # Helper functions for color-output to an Ansi-terminal.
18
+ # ... I have never seen an Ansi-terminal, but learned that about each Linux
19
+ # terminal-emulator can behave like one.
20
+ # And anyway. This works.
21
+
22
+ COLORS = {:default => 9, :black => 0, :red => 1, :green => 2, :yellow => 3, :blue => 4, :purple => 5, :cyan => 6, :white => 7 }
23
+
24
+ BG = 4
25
+ FG = 3
26
+ REGULAR = 0
27
+ BOLD = 1
28
+ UNDERLINE = 4
29
+ BLINK = 5
30
+ SWAP = 7
31
+ NEUTRAL = 0
32
+
33
+ STYLES = {:regular => REGULAR, :bold => BOLD, :underline => UNDERLINE, :blink => BLINK, :swap => SWAP, :neutral => NEUTRAL}
34
+
35
+ def colored_text(text, color_code)
36
+ "#{color_code}#{text}e[0m"
37
+ end
38
+
39
+ def colored_output(output_text, fg_color = :default, bg_color = :default, style = :regular , mode = :neutral )
40
+ "\033[%i;%i;%i%i;%i%im%s\033[0m" %[STYLES[mode.to_sym], STYLES[style.to_sym], FG, COLORS[fg_color.to_sym], BG, COLORS[bg_color.to_sym], output_text]
41
+ end
42
+
43
+ def red(text); colorize(text, "\033[31m"); end
44
+ def green(text); colorize(text, "\033[32m"); end
45
+