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 +5 -0
- data/Manifest.txt +6 -0
- data/README.txt +65 -0
- data/Rakefile +15 -0
- data/lib/box_layout.rb +154 -0
- data/test/test_box_layout.rb +150 -0
- metadata +59 -0
data/History.txt
ADDED
data/Manifest.txt
ADDED
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:
|