html2slideshow 2.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 (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