box_layout 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.
data/History.txt ADDED
@@ -0,0 +1,5 @@
1
+ == 1.0.0 / 2007-03-24
2
+
3
+ * 1 major enhancement
4
+ * Birthday!
5
+
data/Manifest.txt ADDED
@@ -0,0 +1,6 @@
1
+ History.txt
2
+ Manifest.txt
3
+ README.txt
4
+ Rakefile
5
+ lib/box_layout.rb
6
+ test/test_box_layout.rb
data/README.txt ADDED
@@ -0,0 +1,65 @@
1
+ BoxParse
2
+ ported to ruby by Ryan Davis, ryand-ruby@zenspider.com
3
+ http://seattlerb.rubyforge.org/
4
+
5
+ == DESCRIPTION:
6
+
7
+ Allows you to lay out HTML using ASCII art. Stolen from psykotic's
8
+ code posted to reddit: http://programming.reddit.com/info/k9dx/comments
9
+
10
+ == SYNOPSIS:
11
+
12
+ require 'box_layout'
13
+
14
+ page_template = <<-END
15
+ ----------
16
+ | |
17
+ ----------
18
+ | | | |
19
+ | | | |
20
+ | | | |
21
+ | | | |
22
+ ----------
23
+ | |
24
+ ----------
25
+ END
26
+
27
+ layout = BoxLayout.html page_template
28
+ puts "<title>cute</title>"
29
+ puts "<style>* { border: 1px solid black }</style>"
30
+ puts layout % %w[header left body right footer].map {|s| "**#{s}**" }
31
+
32
+ == REQUIREMENTS:
33
+
34
+ * ruby 1.8+
35
+ * rubygems
36
+ * hoe
37
+
38
+ == INSTALL:
39
+
40
+ * sudo gem install box_layout
41
+
42
+ == LICENSE:
43
+
44
+ (The MIT License)
45
+
46
+ Copyright (c) 2007 Ryan Davis, ryand-ruby@zenspider.com
47
+
48
+ Permission is hereby granted, free of charge, to any person obtaining
49
+ a copy of this software and associated documentation files (the
50
+ 'Software'), to deal in the Software without restriction, including
51
+ without limitation the rights to use, copy, modify, merge, publish,
52
+ distribute, sublicense, and/or sell copies of the Software, and to
53
+ permit persons to whom the Software is furnished to do so, subject to
54
+ the following conditions:
55
+
56
+ The above copyright notice and this permission notice shall be
57
+ included in all copies or substantial portions of the Software.
58
+
59
+ THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
60
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
61
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
62
+ IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
63
+ CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
64
+ TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
65
+ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/Rakefile ADDED
@@ -0,0 +1,15 @@
1
+ # -*- ruby -*-
2
+
3
+ require 'rubygems'
4
+ require 'hoe'
5
+ require './lib/box_layout.rb'
6
+
7
+ Hoe.new('box_layout', BoxLayout::VERSION) do |p|
8
+ p.rubyforge_name = 'seattlerb'
9
+ p.summary = 'Allows you to lay out HTML using ASCII art.'
10
+ p.description = p.paragraphs_of('README.txt', 2..5).join("\n\n")
11
+ p.url = p.paragraphs_of('README.txt', 0).first[/http.*/]
12
+ p.changes = p.paragraphs_of('History.txt', 0..1).join("\n\n")
13
+ end
14
+
15
+ # vim: syntax=Ruby
data/lib/box_layout.rb ADDED
@@ -0,0 +1,154 @@
1
+ #!/usr/local/bin/ruby -w
2
+
3
+ require 'set'
4
+
5
+ class Box
6
+ attr_accessor :x, :y, :right, :bottom
7
+ def initialize(x, y, right, bottom)
8
+ @x, @y, @right, @bottom = x, y, right, bottom
9
+ end
10
+
11
+ def == o
12
+ x = o.x and y = o.y and right == o.right and bottom == o.bottom
13
+ end
14
+ alias :eql? :==
15
+
16
+ def hash
17
+ [x, y, right, bottom].hash
18
+ end
19
+
20
+ def inspect
21
+ "Box[x=%d, y=%d, r=%d, b=%d]" % [x, y, right, bottom]
22
+ end
23
+ end
24
+
25
+ class BoxLayout
26
+ VERSION = '1.0.0'
27
+
28
+ def self.html(str)
29
+ layout = self.new
30
+ layout.parse(str)
31
+ layout.to_s
32
+ end
33
+
34
+ attr_reader :boxes, :grid
35
+ def initialize
36
+ @grid = []
37
+ @boxes = []
38
+ end
39
+
40
+ def parse(str)
41
+ @grid = str.strip.split(/\n/)
42
+ @boxes = [] # in case some dork is calling parse multiple times
43
+
44
+ grid.size.times do |y|
45
+ grid[y].size.times do |x|
46
+ if %w(- |).include? self[x, y] and
47
+ self[x, y + 1] == '|' and
48
+ self[x + 1, y] == '-' then
49
+ boxes << Box.new(x, y, box_right(x, y), box_bottom(x, y))
50
+ end
51
+ end
52
+ end
53
+ return boxes
54
+ end
55
+
56
+ def to_s
57
+ rowspans, colspans = box_rowspans, box_colspans
58
+ table = "<table border=\"border\">\n"
59
+ box_rows.each do |row|
60
+ table += " <tr>\n"
61
+ row.each do |box|
62
+ r, c = rowspans[box], colspans[box]
63
+ table += " <td"
64
+ table += " rowspan=\"%d\"" % r if r > 1
65
+ table += " colspan=\"%d\"" % c if c > 1
66
+ table += ">%s</td>\n"
67
+ end
68
+ table += " </tr>\n"
69
+ end
70
+ table += "</table>"
71
+ table
72
+ end
73
+
74
+ def box_x_delimeters
75
+ boxes.map { |box| box.right }.uniq.sort
76
+ end
77
+
78
+ def box_y_delimeters
79
+ boxes.map { |box| box.bottom }.uniq.sort
80
+ end
81
+
82
+ def box_rowspans
83
+ rowspans = Hash.new(0)
84
+ boxes.each do |box| rowspans[box] = 0 end
85
+
86
+ box_y_delimeters.each do |delim|
87
+ boxes.each do |box|
88
+ rowspans[box] += 1 if box.y < delim and box.bottom >= delim
89
+ end
90
+ end
91
+
92
+ rowspans
93
+ end
94
+
95
+ def box_colspans
96
+ colspans = Hash.new(0)
97
+ boxes.each do |box| colspans[box] = 0 end
98
+
99
+ box_x_delimeters.each do |delim|
100
+ boxes.each do |box|
101
+ colspans[box] += 1 if box.x < delim and box.right >= delim
102
+ end
103
+ end
104
+
105
+ colspans
106
+ end
107
+
108
+ def box_rows
109
+ rows, boxes_left = [], boxes.uniq
110
+ box_y_delimeters.each do |delim|
111
+ boxes_in_row, boxes_left = boxes_left.partition { |box| box.y < delim }
112
+ rows.push(boxes_in_row.sort_by { |box| box.x })
113
+ end
114
+ rows
115
+ end
116
+
117
+ # Rendering and parsing tables.
118
+
119
+ def [](x, y)
120
+ grid[y][x].chr rescue " "
121
+ end
122
+
123
+ def box_right(x, y)
124
+ # todo: find
125
+ (x..grid[y+1].size).each do |right|
126
+ return right if self[right + 1, y + 1] == '|'
127
+ end
128
+ raise "Unterminated box. c=#{self[x, y].inspect}"
129
+ end
130
+
131
+ def box_bottom(x, y)
132
+ # todo: find
133
+ (y..grid.size).each do |bottom|
134
+ return bottom if self[x + 1, bottom + 1] == '-'
135
+ end
136
+ raise "Unterminated box. c=#{self[x, y].inspect}"
137
+ end
138
+
139
+ def parse_ascii_table(table)
140
+ grid = table.strip.split(/\n/)
141
+ boxes = []
142
+
143
+ grid.size.times do |y|
144
+ grid[y].size.times do |x|
145
+ if %w(- |).include? self[x, y] and
146
+ self[x, y + 1] == '|' and
147
+ self[x + 1, y] == '-' then
148
+ boxes << Box.new(x, y, box_right(x, y), box_bottom(x, y))
149
+ end
150
+ end
151
+ end
152
+ return boxes
153
+ end
154
+ end
@@ -0,0 +1,150 @@
1
+ #!/usr/local/bin/ruby -w
2
+
3
+ require 'test/unit'
4
+ require 'box_layout'
5
+
6
+ class TestBoxLayout < Test::Unit::TestCase
7
+ def setup
8
+ @grid = "
9
+ ---------
10
+ | | |
11
+ ---------
12
+ | |
13
+ ---------
14
+ ".strip.split(/\n/)
15
+
16
+ @layout = BoxLayout.new
17
+ @layout.parse(@grid.join("\n"))
18
+
19
+ @boxes = []
20
+ @boxes << Box.new(0, 0, 3, 1)
21
+ @boxes << Box.new(4, 0, 7, 1)
22
+ @boxes << Box.new(0, 2, 7, 3)
23
+
24
+ @expected_html = "
25
+ <table border=\"border\">
26
+ <tr>
27
+ <td>%s</td>
28
+ <td>%s</td>
29
+ </tr>
30
+ <tr>
31
+ <td colspan=\"2\">%s</td>
32
+ </tr>
33
+ </table>
34
+ ".strip
35
+
36
+
37
+ end
38
+
39
+ def test_class_html
40
+ html = BoxLayout.html(@grid.join("\n"))
41
+ assert_equal @expected_html, html
42
+ end
43
+
44
+ def test_class_html_big
45
+ table = "
46
+ ---------------------------
47
+ | | | |
48
+ | | | |
49
+ | | | |
50
+ | |-------| |
51
+ | | | |
52
+ | | |-------|
53
+ | | | |
54
+ | | | |
55
+ |---------| |-------|
56
+ | | | | |
57
+ | | |-------| |
58
+ | | | | |
59
+ | | | | |
60
+ | | | | |
61
+ ---------------------------
62
+ "
63
+ expected = "<table border=\"border\">
64
+ <tr>
65
+ <td rowspan=\"3\" colspan=\"2\">%s</td>
66
+ <td>%s</td>
67
+ <td rowspan=\"2\">%s</td>
68
+ </tr>
69
+ <tr>
70
+ <td rowspan=\"3\">%s</td>
71
+ </tr>
72
+ <tr>
73
+ <td>%s</td>
74
+ </tr>
75
+ <tr>
76
+ <td rowspan=\"2\">%s</td>
77
+ <td rowspan=\"2\">%s</td>
78
+ <td rowspan=\"2\">%s</td>
79
+ </tr>
80
+ <tr>
81
+ <td>%s</td>
82
+ </tr>
83
+ </table>"
84
+
85
+ html = BoxLayout.html(table)
86
+ assert_equal expected, html
87
+ end
88
+
89
+ def test_to_s
90
+ assert_equal @expected_html, @layout.to_s
91
+ end
92
+
93
+ def test_char
94
+ assert_equal '-', @layout[0, 0]
95
+ assert_equal '|', @layout[0, 1]
96
+ assert_equal '-', @layout[0, 2]
97
+ assert_equal '-', @layout[1, 0]
98
+ assert_equal '-', @layout[2, 0]
99
+ assert_equal ' ', @layout[1, 1]
100
+ end
101
+
102
+ def test_box_bottom
103
+ assert_equal(1, @layout.box_bottom(0, 0))
104
+ assert_equal(3, @layout.box_bottom(0, 2))
105
+ assert_equal(3, @layout.box_bottom(4, 2))
106
+ assert_equal(3, @layout.box_bottom(7, 2))
107
+ end
108
+
109
+ def test_box_right
110
+ assert_equal(3, @layout.box_right(0, 0))
111
+ assert_equal(7, @layout.box_right(0, 2))
112
+ assert_equal(7, @layout.box_right(4, 2))
113
+ assert_equal(7, @layout.box_right(7, 2))
114
+ end
115
+
116
+ def test_box_colspans
117
+ expect = {
118
+ @boxes[0] => 1,
119
+ @boxes[1] => 1,
120
+ @boxes[2] => 2,
121
+ }
122
+ assert_equal expect, @layout.box_colspans
123
+ end
124
+
125
+ def test_box_rowspans
126
+ expect = {
127
+ @boxes[0] => 1,
128
+ @boxes[1] => 1,
129
+ @boxes[2] => 1,
130
+ }
131
+ assert_equal expect, @layout.box_rowspans
132
+ end
133
+
134
+ def test_box_rows
135
+ assert_equal [@boxes[0..1], [@boxes[2]]], @layout.box_rows
136
+ end
137
+
138
+ def test_box_x_delimeters
139
+ assert_equal [3, 7], @layout.box_x_delimeters
140
+ end
141
+
142
+ def test_box_y_delimeters
143
+ assert_equal [1, 3], @layout.box_y_delimeters
144
+ end
145
+
146
+ def test_parse
147
+ result = @layout.parse(@grid.join("\n"))
148
+ assert_equal @boxes, result
149
+ end
150
+ end
metadata ADDED
@@ -0,0 +1,59 @@
1
+ --- !ruby/object:Gem::Specification
2
+ rubygems_version: 0.9.0.9
3
+ specification_version: 1
4
+ name: box_layout
5
+ version: !ruby/object:Gem::Version
6
+ version: 1.0.0
7
+ date: 2007-03-24 00:00:00 -07:00
8
+ summary: Allows you to lay out HTML using ASCII art.
9
+ require_paths:
10
+ - lib
11
+ email: ryand-ruby@zenspider.com
12
+ homepage: http://seattlerb.rubyforge.org/
13
+ rubyforge_project: seattlerb
14
+ description: "Allows you to lay out HTML using ASCII art. Stolen from psykotic's code posted to reddit: http://programming.reddit.com/info/k9dx/comments == SYNOPSIS: require 'box_layout' page_template = <<-END ---------- | | ---------- | | | | | | | | | | | | | | | | ---------- | | ---------- END layout = BoxLayout.html page_template puts \"<title>cute</title>\" puts \"<style>* { border: 1px solid black }</style>\" puts layout % %w[header left body right footer].map {|s| \"**#{s}**\" } == REQUIREMENTS:"
15
+ autorequire:
16
+ default_executable:
17
+ bindir: bin
18
+ has_rdoc: true
19
+ required_ruby_version: !ruby/object:Gem::Version::Requirement
20
+ requirements:
21
+ - - ">"
22
+ - !ruby/object:Gem::Version
23
+ version: 0.0.0
24
+ version:
25
+ platform: ruby
26
+ signing_key:
27
+ cert_chain:
28
+ post_install_message:
29
+ authors:
30
+ - Ryan Davis
31
+ files:
32
+ - History.txt
33
+ - Manifest.txt
34
+ - README.txt
35
+ - Rakefile
36
+ - lib/box_layout.rb
37
+ - test/test_box_layout.rb
38
+ test_files:
39
+ - test/test_box_layout.rb
40
+ rdoc_options: []
41
+
42
+ extra_rdoc_files: []
43
+
44
+ executables: []
45
+
46
+ extensions: []
47
+
48
+ requirements: []
49
+
50
+ dependencies:
51
+ - !ruby/object:Gem::Dependency
52
+ name: hoe
53
+ version_requirement:
54
+ version_requirements: !ruby/object:Gem::Version::Requirement
55
+ requirements:
56
+ - - ">="
57
+ - !ruby/object:Gem::Version
58
+ version: 1.2.0
59
+ version: