html2slideshow 2.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (45) hide show
  1. checksums.yaml +7 -0
  2. data/bin/html2slideshow +27 -0
  3. data/doc/changes.txt +162 -0
  4. data/doc/license.txt +674 -0
  5. data/lib/LANG +1 -0
  6. data/lib/about.rb +57 -0
  7. data/lib/argparser.rb +143 -0
  8. data/lib/completable.rb +157 -0
  9. data/lib/configurator.rb +155 -0
  10. data/lib/copyright.txt +22 -0
  11. data/lib/extstring.rb +75 -0
  12. data/lib/file_checking.rb +153 -0
  13. data/lib/html2slideshow.cfg +22 -0
  14. data/lib/html2slideshow.rb +132 -0
  15. data/lib/htmlbuilder.rb +267 -0
  16. data/lib/icons/failure.png +0 -0
  17. data/lib/icons/howto.png +0 -0
  18. data/lib/icons/logo.png +0 -0
  19. data/lib/icons/message.png +0 -0
  20. data/lib/icons/options.png +0 -0
  21. data/lib/icons/question.png +0 -0
  22. data/lib/icons/success.png +0 -0
  23. data/lib/image.rb +62 -0
  24. data/lib/list_fields.rb +34 -0
  25. data/lib/log.conf +60 -0
  26. data/lib/logging.rb +194 -0
  27. data/lib/slideshow_css.rb +248 -0
  28. data/lib/slideshow_images/downCursor.png +0 -0
  29. data/lib/slideshow_images/leftArrow.png +0 -0
  30. data/lib/slideshow_images/olive.png +0 -0
  31. data/lib/slideshow_images/pause.png +0 -0
  32. data/lib/slideshow_images/rightArrow.png +0 -0
  33. data/lib/slideshow_images/sizeMedium.png +0 -0
  34. data/lib/slideshow_images/sizeNormal.png +0 -0
  35. data/lib/slideshow_images/sizeSmall.png +0 -0
  36. data/lib/slideshow_images/start.png +0 -0
  37. data/lib/slideshow_images/stop.png +0 -0
  38. data/lib/slideshow_images/toggle.png +0 -0
  39. data/lib/slideshow_images/upCursor.png +0 -0
  40. data/lib/slideshow_js.rb +390 -0
  41. data/lib/slideshow_template.rb +194 -0
  42. data/lib/sourcefile.rb +191 -0
  43. data/lib/translating.rb +90 -0
  44. data/lib/translations +354 -0
  45. metadata +86 -0
data/lib/about.rb ADDED
@@ -0,0 +1,57 @@
1
+ #encoding: UTF-8
2
+ =begin
3
+ /***************************************************************************
4
+ * Copyright © 2008-2017, 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 GNU General Public License as published by *
8
+ * the Free Software Foundation; either version 3 of the License, or *
9
+ * (at your option) any later version. *
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. See the *
14
+ * GNU General Public License for more details. *
15
+ * *
16
+ * You should have received a copy of the GNU General Public License *
17
+ * along with this program; if not, write to the *
18
+ * Free Software Foundation, Inc., *
19
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
20
+ ***************************************************************************/
21
+ =end
22
+
23
+
24
+ $APPNAME='Html2Slideshow'
25
+
26
+ $VERSION='2.0'
27
+
28
+ $AUTHOR='Michael Uplawski'
29
+ $EMAIL = '<michael.uplawski@uplawski.eu>'
30
+
31
+ $WEB_SITE='https://rubygems.org'
32
+
33
+ $YEARS='2008 - 2022'
34
+
35
+ $SYSTEM=`uname -a`
36
+
37
+ $LICENSE_NAME='GPL-3.0'
38
+
39
+ $COPYRIGHT=format("Copyright © %s, %s\n\t%s", $YEARS, $AUTHOR, $EMAIL)
40
+
41
+ $LICENSE="This program is free software; you can redistribute it
42
+ and/or modify it under the terms of the GNU General Public
43
+ License as published by the Free Software Foundation; either
44
+ version 3 of the License, or (at your option) any later
45
+ version.
46
+ This program is distributed in the hope that it will
47
+ be useful, but WITHOUT ANY WARRANTY; without even the implied
48
+ warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
49
+ See the GNU General Public License for more details.
50
+ You should have received a copy of the GNU General Public License
51
+ along with this program; if not, write to the
52
+
53
+ Free Software Foundation, Inc.,
54
+ 59 Temple Place - Suite 330,
55
+ Boston, MA
56
+ 02111-1307,
57
+ USA."
data/lib/argparser.rb ADDED
@@ -0,0 +1,143 @@
1
+ #encoding: UTF-8
2
+ =begin
3
+ /***************************************************************************
4
+ * Copyright © 2008-2022, 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 GNU General Public License as published by *
8
+ * the Free Software Foundation; either version 3 of the License, or *
9
+ * (at your option) any later version. *
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. See the *
14
+ * GNU General Public License for more details. *
15
+ * *
16
+ * You should have received a copy of the GNU General Public License *
17
+ * along with this program; if not, write to the *
18
+ * Free Software Foundation, Inc., *
19
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
20
+ ***************************************************************************/
21
+ =end
22
+
23
+ require 'optparse'
24
+ require 'optparse/time'
25
+ require 'ostruct'
26
+ require_relative 'image'
27
+ require_relative 'translating'
28
+ require_relative 'about'
29
+ require_relative 'logging'
30
+ require_relative 'extstring'
31
+
32
+ class ArgParser
33
+ include Logging
34
+
35
+ PREFIX = '/usr/local'
36
+ SUPPLDIR = "#{PREFIX}/share/#{$APPNAME}"
37
+
38
+ CODES = %w[iso-2022-jp shift_jis euc-jp utf8 binary]
39
+ CODE_ALIASES = { "jis" => "iso-2022-jp", "sjis" => "shift_jis" }
40
+
41
+ self::extend(Logging)
42
+ @@log = self::init_logger()
43
+
44
+ # Returns a structure describing the options.
45
+ #
46
+ def self.parse(args)
47
+ # The options specified on the command line will be collected in <b>options</b>.
48
+ # We set default values here.
49
+ options = OpenStruct.new
50
+ options.source = './'
51
+ options.target = './'
52
+ options.config = SUPPLDIR + File::Separator + 'html2slideshow.cfg'
53
+ options.debug = false
54
+ options.debug_dir = nil
55
+ options.source_type = 'HTML' # 'files' if not 'HTML'
56
+ options.recursive = false
57
+
58
+ # can be a space-separated list.
59
+ options.formats = "jpg"
60
+
61
+ op = OptionParser.new do |opts|
62
+ opts.banner = trl("Usage") << ":\truby #{$APPNAME}.rb [options]\n\t" << trl("or") << " #{$APPNAME} [options]"
63
+
64
+ opts.separator ""
65
+ opts.separator trl("Specific options") << ':'
66
+
67
+ opts.on(trl("-f"), '--' << trl("formats") << " [\"" << Image::FORMATS.keys.collect{|f| f.to_s}.join(', ') << "\"]", trl("specify the comma-separated list of image formats,"), trl("which should be used, others will be ignored.") ) do |iforms|
68
+
69
+ options.formats = iforms.split(',').collect do |f|
70
+ f.strip!
71
+ f.downcase!
72
+ f.delete!('e') if f != 'webp'
73
+ format = Image::FORMATS[f.to_sym]
74
+ if !format
75
+ @log.error('Not a supported image format: ' << f << ". Choose from " << Image::FORMATS.keys.collect{|f| f.to_s}.join(', '))
76
+ @log.error("Aborting. Bye.")
77
+ exit false
78
+ end
79
+ format
80
+ end
81
+ @log.debug('storing formats in options : ' << options.to_s)
82
+ end
83
+
84
+ opts.on(trl("-d"), '--' << trl("debug [true|FALSE]"), trl("Switch on debug-mode."), trl("Will generate log-messages during processing") ) do |deb|
85
+ options.debug = (deb && deb.chomp.downcase == 'false' ? nil : true)
86
+ @log.level = Logger::DEBUG if options.debug
87
+ end
88
+ opts.on(trl("-l"), '--' << trl("local"), trl("Collect the image-files from the source-directory"), trl("(if not provided, HTML-files are analyzed)") ) do |l|
89
+ options.source_type = 'files'
90
+ end
91
+
92
+ opts.on(trl("-r"),'--' << trl("recursive"), trl("When collecting image-files from the source-directory,"), trl("also include the sub-directories.")) do |l|
93
+ options.recursive = true
94
+ end
95
+
96
+ opts.on(trl("-s"), '--' << trl("source SOURCE DIR"), trl("Read HTML source-files from this directory")) do |source|
97
+ options.source = File.expand_path(source)
98
+ options.target = options.source
99
+ end
100
+ opts.on(trl("-t"), '--' << trl("target [TARGET DIR]"), trl("Write slideshow-files to this sub-directory"), " " << trl("(if not provided, SOURCE DIR is used)")) do |target|
101
+ sd = File.expand_path(options.source)
102
+ sd << File::Separator if (!sd.end_with?(File::Separator) )
103
+ options.target = sd << target
104
+ end
105
+
106
+ =begin
107
+ opts.on("-c", "--config [CONFIG FILE]",
108
+ "Read alternative configuration from this file") do |conf|
109
+ $LOG.debug("config-file should be #{conf}") if $LOG
110
+ options.config = File.expand_path(conf )
111
+ end
112
+ opts.on("-g", "--generic [CONFIG FILE]",
113
+ "Write generic configuration options to this file") do |file|
114
+ options.generic = File.expand_path(file )
115
+ end
116
+ =end
117
+ opts.separator ""
118
+ opts.separator trl("Common options") << ':'
119
+
120
+ # No argument, shows at tail. This will print an options summary.
121
+ # Try it and see!
122
+ # show help
123
+ opts.on_tail(trl("-h"), '--' << trl("help"), trl("Show this message")) do
124
+ puts opts
125
+ exit
126
+ end
127
+
128
+ # Another typical switch to print the version.
129
+ opts.on_tail('--' << trl("version"), trl("Show version")) do
130
+ msg = "\t#{$APPNAME}, " << trl("version") << " #{$VERSION}"
131
+ msg << "\n\t#{$COPYRIGHT}"
132
+ msg << "\n\n%50s" %($LICENSE)
133
+ puts msg.box(:padding => 2, :left => 2, :top => 1)
134
+ exit
135
+ end
136
+ end
137
+
138
+ op.parse!(args)
139
+ options
140
+ end # parse()
141
+
142
+ end
143
+
@@ -0,0 +1,157 @@
1
+ #encoding: UTF-8
2
+ =begin
3
+ /***************************************************************************
4
+ * Copyright © 2008-2017, 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 GNU General Public License as published by *
8
+ * the Free Software Foundation; either version 3 of the License, or *
9
+ * (at your option) any later version. *
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. See the *
14
+ * GNU General Public License for more details. *
15
+ * *
16
+ * You should have received a copy of the GNU General Public License *
17
+ * along with this program; if not, write to the *
18
+ * Free Software Foundation, Inc., *
19
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
20
+ ***************************************************************************/
21
+ =end
22
+
23
+ require_relative 'logging'
24
+ # Completable file-objects can treat their
25
+ # contents like a fillable form. Predefined
26
+ # fields are searched and replaced by values.
27
+
28
+ module Completable
29
+
30
+ include Logging
31
+ attr_reader :backup, :summary
32
+
33
+ # The main function of this module.
34
+ # Expects as parameters a Hash of field/substituion-
35
+ # pairs and an optional block.
36
+ # If a block is given, the original file will
37
+ # be processed and a backup is created.
38
+
39
+ def complete(subst_def, &b)
40
+
41
+ init_logger()
42
+ @summary = Summary.new(subst_def)
43
+ @field_count = 0
44
+ if(self.respond_to?(:gets) )
45
+ if(self.respond_to?(:closed?) && !self.closed?)
46
+ self.rewind
47
+ if(subst_def && subst_def.respond_to?(:has_key?))
48
+ cpos = 0
49
+ if(!b)
50
+ @backup="#{self.path}_backup"
51
+ outfile = File.open(@backup, 'w'){|bf| bf.write(self.readlines() )}
52
+ self.rewind
53
+ end
54
+ while(chunk = self.gets())
55
+ chunk, msg = process(chunk, subst_def)
56
+ if(!chunk && msg)
57
+ return nil, msg
58
+ end
59
+ if(b)
60
+ b.call(chunk)
61
+ else
62
+ self.seek(cpos, IO::SEEK_SET)
63
+ self.write(chunk)
64
+ end
65
+ cpos = self.pos
66
+ end
67
+ else
68
+ return nil, 'first parameter must be a Hash'
69
+ end
70
+ else
71
+ return nil, 'completable object must at least be open for reading'
72
+ end
73
+ else
74
+ return nil, 'completable object must also respond to :gets'
75
+ end
76
+ @field_count
77
+ end
78
+
79
+ # sets the character sequence, which marks
80
+ # substitutable text
81
+ def field_delimiter=(d)
82
+ @field_delimiter = d
83
+ @field_regex = Regexp.new("#{d}[^#{d}]*#{d.reverse}")
84
+ end
85
+ # returns the character sequence, which marks
86
+ # substitutable text
87
+ def field_delimiter()
88
+ if(!@field_delimiter)
89
+ field_delimiter=(' ')
90
+ end
91
+ @field_delimiter
92
+ end
93
+
94
+ private
95
+
96
+ # processes one chunk of text with the given
97
+ # map of field/substitution pairs
98
+ def process(chunk, subst_def)
99
+ if(@field_regex)
100
+ # rpl = chunk.match(@field_regex)
101
+ begin
102
+ fields = chunk.force_encoding("UTF-8").scan(@field_regex)
103
+ rescue ArgumentError => er
104
+ @log.error("ERROR: " << er.message);
105
+ @log.error("chunk is: " << chunk.to_s)
106
+ @log.error("encoding: " << chunk.encoding().to_s)
107
+ end
108
+ fields.each do |rpl|
109
+ if rpl
110
+ # offset = rpl.offset(0) if rpl
111
+ offset = chunk.index(rpl)
112
+ test_key = rpl.to_s.delete(@field_delimiter)
113
+ if(subst_def.has_key?(test_key))
114
+ @summary.add_found(test_key)
115
+ value = subst_def[test_key]
116
+ chunk.gsub!(rpl.to_s, value) if value
117
+ @field_count += 1
118
+ end
119
+ end
120
+ end
121
+ chunk
122
+ else
123
+ return nil, 'field-delimiter must be set.'
124
+ end
125
+ end
126
+
127
+ # a class to summarize processing results
128
+ class Summary
129
+ attr_accessor :fields_found
130
+
131
+ def fields_missing
132
+ if(@fields_found)
133
+ @fields - @fields_found.keys
134
+ else
135
+ @fields
136
+ end
137
+ end
138
+
139
+ def initialize(fields)
140
+ if fields.respond_to?(:keys)
141
+ @fields = Array.new(fields.keys)
142
+ elsif fields.respond_to?(:to_ary)
143
+ @fields = Array.new(fields)
144
+ else
145
+ @fields = Array.new()
146
+ end
147
+ @fields_found = Hash.new
148
+ end
149
+
150
+ def add_found(field)
151
+ count = @fields_found[field]
152
+ count = 0 if !count
153
+ @fields_found[field] = count + 1
154
+ end
155
+ end
156
+ end
157
+
@@ -0,0 +1,155 @@
1
+ #encoding: UTF-8
2
+ =begin
3
+ /***************************************************************************
4
+ * Copyright © 2008-2022, 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 GNU General Public License as published by *
8
+ * the Free Software Foundation; either version 3 of the License, or *
9
+ * (at your option) any later version. *
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. See the *
14
+ * GNU General Public License for more details. *
15
+ * *
16
+ * You should have received a copy of the GNU General Public License *
17
+ * along with this program; if not, write to the *
18
+ * Free Software Foundation, Inc., *
19
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
20
+ ***************************************************************************/
21
+ =end
22
+
23
+ RD = File.expand_path(File.dirname(__FILE__) ) + File::Separator if !defined?(RD)
24
+ require 'date'
25
+ require 'yaml'
26
+ require 'ostruct'
27
+ require_relative 'file_checking'
28
+ require_relative 'logging'
29
+ require 'singleton'
30
+
31
+ =begin
32
+ This class reads and writes configuration data.
33
+ =end
34
+ class Configurator
35
+ include File_Checking
36
+ include Logging
37
+
38
+ # default configuration will be overwritten with
39
+ # user-defined values.
40
+ #
41
+ # There shall be no instance-variables!
42
+ #
43
+ CONFIG = format("%shtml2slideshow.cfg", RD)
44
+
45
+ def initialize(opts = nil)
46
+ init_logger()
47
+ @configurations = Hash.new
48
+ init_config(opts)
49
+ @log.debug(format("opts are of type %s", opts.class)) if @log
50
+ end
51
+
52
+ def method_missing(method, args = nil)
53
+ @log.debug("requested value for #{method}: #{@configurations[method]}") if @log
54
+ if(@configurations.has_key?(method))
55
+ @configurations[method]
56
+ else
57
+ super
58
+ end
59
+ end
60
+
61
+ # combines the values from the parameter-object and
62
+ # those, already present in the existing configuration
63
+ def consolidate_configuration(cfg)
64
+ if(cfg.respond_to?(:each_key))
65
+ cfg.each_key {|k| @configurations[k] = cfg[k] if cfg[k]}
66
+ end
67
+ end
68
+
69
+ def complete_configuration(cfg)
70
+ if(cfg.respond_to?(:each_key))
71
+ @configurations.each_key do |k|
72
+ if(! cfg.has_key?(k) )
73
+ cfg[k] = @configurations[k]
74
+ end
75
+ end
76
+ end
77
+ cfg
78
+ end
79
+ def save(opts)
80
+ @log.debug(format("shall write options to config-file", CONFIG)) if @log
81
+ @configurations = complete_configuration(opts)
82
+ if(!File.exist?(CONFIG) || !file_check(CONFIG, [:file?, :writable?]))
83
+ @configurations[:date] = Time.now.to_s
84
+ @log.debug(format("writing to config-file %s:\n%s", CONFIG, @configurations)) if @log
85
+ File.open(CONFIG, 'w') {|cfg| YAML::dump(@configurations, cfg)}
86
+ end
87
+ end
88
+
89
+ # The initial default configuration is merged with program options, or
90
+ # those from the configuration file.
91
+ def init_config(opts = nil)
92
+ if (!@configurations || @configurations.empty?)
93
+ @configurations = {
94
+ :date => Time.now.to_s,
95
+ :formats => Image::FORMATS,
96
+ :target => './',
97
+ :source => './',
98
+ :suffix => '_slideshow',
99
+ :source_type => 'HTML',
100
+ :recursive => false,
101
+ :browser => 'firefox',
102
+ :log => '/tmp/html2slideshow.log',
103
+ :merge => false,
104
+ :scale_medium => '500',
105
+ :scale_small => '300',
106
+ :title => '',
107
+ }
108
+ end
109
+ if(opts)
110
+ if opts.respond_to?(:delete_field)
111
+ @log.debug('calling read_options')
112
+ read_options(opts)
113
+ elsif opts.respond_to?(:to_hash)
114
+ @log.debug('calling read_hashed_options')
115
+ read_hashed_options(opts)
116
+ end
117
+ else
118
+ read_from_file
119
+ end
120
+ @configurations.freeze
121
+ end
122
+ private
123
+
124
+ def read_hashed_options(options)
125
+ @configurations.merge!(options)
126
+ @log.debug(format("merged configuration is: %s", @configurations.inspect)) if @log
127
+ end
128
+
129
+ def read_options(options)
130
+ @log.debug(format("reading options from %s", options.inspect)) if options && @log
131
+ @log.debug(format("configurations is %s", @configurations.inspect) ) if @log
132
+ @configurations[:formats] = options.formats if options.formats
133
+ @configurations[:recursive] = options.recursive if options.recursive
134
+ @configurations[:source] = options.source if options.source
135
+ @configurations[:target] = options.target if options.target
136
+ @configurations[:browser] = options.browser if options.browser
137
+ @configurations[:scale_small] = options.scale_small if options.scale_small
138
+ @configurations[:scale_medium] = options.scale_medium if options.scale_medium
139
+ @log.debug("configuration is #{@configurations.inspect}") if @log
140
+ end
141
+
142
+ def read_from_file
143
+ if(!file_check(CONFIG, [:exist?, :file?, :readable?]))
144
+ @configurations.merge!( YAML::load_file(CONFIG))
145
+ @log = Logger.new(@configurations[:log]) if @configurations[:log]
146
+ @log.level = Logger::INFO if @log && !@configurations[:debug]
147
+ @log.debug("configuration from File is #{@configurations.inspect}") if @log
148
+ end
149
+ end
150
+ end # end of class definition
151
+
152
+ class Single_Configurator < Configurator
153
+ include Singleton
154
+ end # end of class definition
155
+
data/lib/copyright.txt ADDED
@@ -0,0 +1,22 @@
1
+ =begin
2
+ /***************************************************************************
3
+ * Copyright ©2008-2017, *
4
+ * Michael Uplawski <michael.uplawski@uplawski.de> *
5
+ * *
6
+ * This program is free software; you can redistribute it and/or modify *
7
+ * it under the terms of the GNU General Public License as published by *
8
+ * the Free Software Foundation; either version 3 of the License, or *
9
+ * (at your option) any later version. *
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. See the *
14
+ * GNU General Public License for more details. *
15
+ * *
16
+ * You should have received a copy of the GNU General Public License *
17
+ * along with this program; if not, write to the *
18
+ * Free Software Foundation, Inc., *
19
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
20
+ ***************************************************************************/
21
+ =end
22
+
data/lib/extstring.rb ADDED
@@ -0,0 +1,75 @@
1
+ #encoding: UTF-8
2
+
3
+ if(! String.method_defined?(:end_with?))
4
+ class String
5
+ def end_with?(str)
6
+ isso = false;
7
+ if(str.respond_to?(:to_str) && self.include?(str))
8
+ isso = (slice(rindex(str), (size()-1)) == str)
9
+ end
10
+ return isso
11
+ end
12
+ end
13
+ end
14
+
15
+ class String
16
+ def box(opt = {})
17
+ upleft = "\u250F"
18
+ upright = "\u2513"
19
+ downleft = "\u2517"
20
+ downright = "\u251B"
21
+
22
+ vert = "\u2503"
23
+ hor = "\u2501"
24
+
25
+ max_width = size[0] - 5
26
+
27
+ left = opt[:left]
28
+ top = opt[:top]
29
+ padding = opt[:padding]
30
+ # width = opt[:width]
31
+
32
+ size = `stty size`.split.map { |x| x.to_i }.reverse
33
+
34
+ left ||= 0
35
+ top ||= 0
36
+ padding ||= 0
37
+ # width ||= max_width
38
+ # width = max_width if max_width < width
39
+
40
+ gsub!("\t", ' ')
41
+ width = self.split("\n").max {|l1, l2| l1.length <=> l2.length}.length + 2* padding
42
+
43
+
44
+ box = ''
45
+ box << "\n" * top
46
+ # top border
47
+ box << ' ' * left << upleft.dup << hor.dup * width << upright.dup << "\n"
48
+ # top padding
49
+ box << ' ' * left << vert.dup << ' ' * width << vert.dup << "\n"
50
+ # lines
51
+ self.split("\n").each do |line|
52
+ if(line && !line.empty?)
53
+ nl = ' ' * left << vert.dup << ' ' * padding << line << ' ' * padding
54
+ # wanted length : width + left margin + width of the first vertical border sign
55
+ until(nl.length >= ( width + left +1) )
56
+ nl << ' '
57
+ end
58
+ nl << vert.dup << "\n"
59
+ else
60
+ nl = ' ' * left << vert.dup << ' ' * width << vert.dup << "\n"
61
+ end
62
+ box << nl
63
+ end
64
+ # bottom padding
65
+ box << ' ' * left << vert.dup << ' ' * width << vert.dup << "\n"
66
+ # bottom border
67
+ box << ' ' * left << downleft.dup << hor.dup * width << downright.dup
68
+ return box
69
+ end
70
+
71
+ def box!(opt = {})
72
+ self.replace(String.new(box(opt)))
73
+ end
74
+
75
+ end