box_layout 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- 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:
|