array-formatter 1.0.1

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.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 74c5fcc251fdd3259eb03c4c60aab0cbd067a4a8
4
+ data.tar.gz: b3101c02d554d3b2971752e4154aa7ad06e1b74c
5
+ SHA512:
6
+ metadata.gz: c4e0b8880b25896db9867d8a7439d83b28127fa04dd84895ab083c5cccc9223305291af7b021d78d0023a4d9868fe202a813b655c5e93d64c432267f25dc4b3f
7
+ data.tar.gz: 4698454dc011619bfbd8f75d6bbf1b05b3025c0fd88f5621cf830799c55479bac8e1d97d625eab1244962cc439f3dfce83637e485ea52a01b5300fa8ce33ef0b
@@ -0,0 +1,25 @@
1
+ # Because this is a gem, ignore Gemfile.lock:
2
+
3
+ Gemfile.lock
4
+
5
+ # And because this is Ruby, ignore the following
6
+ # (source: https://github.com/github/gitignore/blob/master/Ruby.gitignore):
7
+
8
+ *.gem
9
+ *.rbc
10
+ .bundle
11
+ .config
12
+ coverage
13
+ InstalledFiles
14
+ lib/bundler/man
15
+ pkg
16
+ rdoc
17
+ spec/reports
18
+ test/tmp
19
+ test/version_tmp
20
+ tmp
21
+
22
+ # YARD artifacts
23
+ .yardoc
24
+ _yardoc
25
+ doc/
data/Gemfile ADDED
@@ -0,0 +1,3 @@
1
+ source "https://rubygems.org"
2
+
3
+ gemspec
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2013 Alan K. Stebbens <aks@stebbens.org>
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,50 @@
1
+ # Array::Formatter
2
+
3
+ A simple gem to reformat an array of arrays into one of several formats:
4
+
5
+ - HTML table (as a string)
6
+ - CSV string
7
+ - table (using fixed-width ASCII text or Unicode drawing characters)
8
+ - YAML string
9
+
10
+ ## Installation
11
+
12
+ Add this line to your application's Gemfile:
13
+
14
+ gem 'array-formatter'
15
+
16
+ And then execute:
17
+
18
+ $ bundle
19
+
20
+ Or install it yourself as:
21
+
22
+ $ gem install array-formatter
23
+
24
+ ## Usage
25
+
26
+ require 'array/formatter'
27
+
28
+ array.to_table :ascii
29
+ array.to_table :unicode
30
+ array.to_table :unicode_double
31
+ array.to_table :unicode_single
32
+ array.to_table :unicode_mixed
33
+
34
+ array.to_csv
35
+
36
+ array.to_html
37
+
38
+ array.to_yaml
39
+
40
+ ## Author:
41
+
42
+ Alan K. Stebbens <aks@stebbens.org>
43
+
44
+ ## Contributing
45
+
46
+ 1. Fork it
47
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
48
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
49
+ 4. Push to the branch (`git push origin my-new-feature`)
50
+ 5. Create new Pull Request
@@ -0,0 +1,12 @@
1
+ #require 'rake'
2
+
3
+ require "bundler/gem_tasks"
4
+ require 'rake/testtask'
5
+
6
+ Rake::TestTask.new do |t|
7
+ t.libs << 'lib'
8
+ t.pattern = 'test/**/test[-_]*.rb'
9
+ t.verbose = false
10
+ end
11
+
12
+ task :default => :test
@@ -0,0 +1,26 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'array/formatter/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "array-formatter"
8
+ spec.version = Array::Formatter::VERSION
9
+ spec.authors = ["Alan Stebbens"]
10
+ spec.email = ["aks@stebbens.org"]
11
+ spec.summary = "Format an array of arrays in one of serveral string formats"
12
+ spec.description = <<-EOF
13
+ A simple gem to reformat an array of arrays into one of several string
14
+ formats: HTML table; CSV; ASCII table; YAML
15
+ EOF
16
+ spec.homepage = "https://gitlab.com/as/array-formatter"
17
+ spec.license = "MIT"
18
+
19
+ spec.files = `git ls-files`.split($/)
20
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
21
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
22
+ spec.require_paths = ["lib"]
23
+
24
+ spec.add_development_dependency "bundler", "~> 1.3"
25
+ spec.add_development_dependency "rake"
26
+ end
@@ -0,0 +1,247 @@
1
+ # array-formatter.rb
2
+ #
3
+ # Author: Alan K. Stebbens <aks@stebbens.org>
4
+ #
5
+ # ARRAY.to_html -- format an array of arrays into an HTML table string
6
+ # ARRAY.to_csv -- format an array of arrays into a CSV string
7
+ # ARRAY.to_table -- format an array of arrays into an ASCII table string
8
+ #
9
+
10
+ class Array
11
+
12
+ # string = ARRAY.to_html indent=0
13
+ #
14
+ # Return an HTML representation of an array of arrays as an
15
+ # HTML table. If indent given, indent the <table> by that
16
+ # many spaces.
17
+
18
+ def to_html indent=0
19
+ require 'cgi'
20
+ s = self.wrap_map_html_data("table", indent + 0) do |row, rx|
21
+ row.wrap_map_html_data("tr", indent + 1) do |field, fx|
22
+ tag = rx == 0 ? 'th' : 'td'
23
+ (' ' * (indent + 2)) + # indention
24
+ "<#{tag}>" + # open tag
25
+ (field && CGI.escapeHTML(field) || '') + # cell text
26
+ "</#{tag}>\n" # close tag
27
+ end
28
+ end
29
+ s
30
+ end
31
+
32
+ # string = ARRAY.wrap_map_html_data TAG, INDENT {|DATA, INDEX| block}
33
+ #
34
+ # Return a string HTML representation of an array of data, starting with
35
+ # <TAG> and ending with </TAG>, and invoking the block on each array item,
36
+ # passing the DATA item with its INDEX.
37
+
38
+ def wrap_map_html_data tag, indent=0
39
+ s = ''
40
+ prefix = ' ' * indent
41
+ s << prefix + "<#{tag}>\n"
42
+ self.each_with_index {|data, x| s << ((yield data, x) || '') }
43
+ s << prefix + "</#{tag}>\n"
44
+ s
45
+ end
46
+
47
+ # string = ARRAY.to_csv
48
+ #
49
+ # Convert an array of arrays to CSV representation Basically, each
50
+ # top-level array row becomes a line of CSV data The 2nd level
51
+ # arrays become individual rows of data, separated by commas. Each
52
+ # 2nd level array item gets quoted if it contains any punctuation
53
+ # characters.
54
+
55
+ def to_csv
56
+ self.map {|row| row.map {|f| f =~ /[[:punct:]]/ ? '"' + f.gsub(/"/, '""') + '"' : f }.join(",")}.join("\n")
57
+ end
58
+
59
+ # string = ARRAY.to_table type
60
+ #
61
+ # Convert an array of arrays to ASCII table representation
62
+ #
63
+ # to create a box, we need to describe the parts of it:
64
+ # (be sure to used fixed-width font)
65
+ #
66
+ # +-------+-------+ <== top border
67
+ # | cell1 | cell2 | <== data row
68
+ # +-------+-------+ <== inner border
69
+ # | r2c1 | r2c2 | <== data row
70
+ # +-------+-------+ <== bottom border
71
+ # ^ ^ ^
72
+ # | | +--<== right
73
+ # | +----------<== middle
74
+ # +------------------<== left
75
+ #
76
+ # Given these, there are 15 specific characters for line drawing:
77
+ #
78
+ # Location Symbol Location Symbol
79
+ # ================ ====== ================ ======
80
+ # top-left-border tlb left-inner-border lib
81
+ # top-border tb inner-border ib
82
+ # top-inner-border tib middle-inner-border mib
83
+ # top-right-border trb right-inner-border rib
84
+ #
85
+ # left-data-border ldb bottom-left-border blb
86
+ # inner-data-border idb bottom-border bb
87
+ # right-data-border rdb bottom-inner-border bib
88
+ # bottom-right-border brb
89
+ #
90
+ # In the specs below, the characters are given in the same order as above.
91
+ # The characters are index by the given symbols.
92
+
93
+ class TableChars < Hash
94
+
95
+ @@table_chars = {}
96
+ @@table_char_names = %w( tlb tb tib trb ldb idb rdb lib ib mib rib blb bb bib brb ).map{|n|n.intern}
97
+
98
+ def initialize name, fmt_chars, start=nil, stop=nil
99
+ @chars = self
100
+ @@table_chars[name] = @chars
101
+ if fmt_chars.class == Symbol
102
+ @@table_chars[name] = @chars = @@table_chars[fmt_chars].dup
103
+ elsif fmt_chars.class == Array
104
+ chars = fmt_chars.dup
105
+ @@table_char_names.each{|n| @chars[n] = chars.shift || raise(ArgumentError, "Missing characters from table drawing charset!")}
106
+ end
107
+ @start = start
108
+ @stop = stop
109
+ @chars
110
+ end
111
+
112
+ @@table_char_names.each do |name|
113
+ define_method(name) { @chars[name] }
114
+ end
115
+
116
+ # TableChars.get NAME
117
+ #
118
+ # Return the TableChars object for NAME, or nil
119
+
120
+ def self.get name
121
+ @chars = @@table_chars[name]
122
+ end
123
+
124
+ attr_reader :start, :stop
125
+
126
+ def wrap text
127
+ (@start || '') + text + (@stop || '')
128
+ end
129
+
130
+ end
131
+
132
+ # :ascii -- an ASCII table
133
+
134
+ TableChars.new :ascii, %w( + - + + | | | + - + + + - + + )
135
+
136
+ # :unicode_single - a table with thick outer border, and thin inner lines.
137
+ TableChars.new :unicode_single, [ "\u250F", "\u2501", "\u252F", "\u2513", # tlb, tb, tib, trb
138
+ "\u2503", "\u2502", "\u2503", # ldb, idb, rdb
139
+ "\u2520", "\u2500", "\u253C", "\u2528", # lib, ib, mib, rib
140
+ "\u2517", "\u2501", "\u2537", "\u251B" ] # blb, bb, bib, brb
141
+
142
+ # :unicode_bold - a table with thick borders everywhere
143
+ TableChars.new :unicode_bold, [ "\u250F", "\u2501", "\u2533", "\u2513", # tlb, tb, tib, trb
144
+ "\u2503", "\u2503", "\u2503", # ldb, idb, rdb
145
+ "\u2523", "\u2501", "\u254B", "\u252B", # lib, ib, mib, rib
146
+ "\u2517", "\u2501", "\u253B", "\u251B" ] # blb, bb, bib, brb
147
+
148
+ # :unicode_double - a table with double lines everywhere
149
+ TableChars.new :unicode_double, [ "\u2554", "\u2550", "\u2566", "\u2557", # tlb, tb, tib, trb
150
+ "\u2551", "\u2551", "\u2551", # ldb, idb, rdb
151
+ "\u2560", "\u2550", "\u256C", "\u2563", # lib, ib, mib, rib
152
+ "\u255A", "\u2550", "\u2569", "\u255D" ] # blb, bb, bib, brb
153
+
154
+ # :unicode_mixed - a table with double outer lines, and single inner lines
155
+ TableChars.new :unicode_mixed, [ "\u2554", "\u2550", "\u2564", "\u2557", # tlb, tb, tib, trb
156
+ "\u2551", "\u2502", "\u2551", # ldb, idb, rdb
157
+ "\u2557", "\u2550", "\u253C", "\u2562", # lib, ib, mib, rib
158
+ "\u255A", "\u2550", "\u2567", "\u255D" ] # blb, bb, bib, brb
159
+
160
+ TableChars.new :dos_single, [ "\xDA", "\xC4", "\xC2", "\xBF", # tlb, tb, tib, trb
161
+ "\xB3", "\xB3", "\xB3", # ldb, idb, rdb
162
+ "\xC3", "\xC4", "\xC5", "\xB4", # lib, ib, mib, rib
163
+ "\xC0", "\xC4", "\xC1", "\xD9" ] # blb, bb, bib, brb
164
+
165
+ TableChars.new :dos_double, [ "\xC9", "\xCD", "\xCB", "\xBB", # tlb, tb, tib, trb
166
+ "\xBA", "\xBA", "\xBA", # ldb, idb, rdb
167
+ "\xCC", "\xCD", "\xCE", "\xB9", # lib, ib, mib, rib
168
+ "\xC8", "\xCD", "\xCA", "\xBC" ] # blb, bb, bib, brb
169
+
170
+ TableChars.new :vt100, [ "\x6C", "\x71", "\x77", "\x6B", # tlb, tb, tib, trb
171
+ "\x78", "\x78", "\x78", # ldb, idb, rdb,
172
+ "\x74", "\x71", "\x6E", "\x75", # lib, ib, mib, rib
173
+ "\xCD", "\x71", "\x76", "\x6A" ], # blb, bb, bib, brb
174
+ "\e(0", "\e(B"
175
+
176
+ TableChars.new :unicode, :unicode_single
177
+ TableChars.new :dos, :dos_single
178
+
179
+
180
+ def to_table name=:ascii
181
+ @chars = TableChars.get name
182
+
183
+ # compute the maximum widths and the alignment of each column
184
+ @widths = []
185
+ @align = []
186
+ self.each_with_index do |row,rx|
187
+ row.each_with_index do |col,cx|
188
+ @widths[cx] ||= 0
189
+ l = col.to_s.length
190
+ @widths[cx] = l if l > @widths[cx]
191
+ if rx == 0
192
+ type = nil
193
+ else
194
+ type = case (col || '')
195
+ when /^\$?\s*\d[,\d]*\.\d*$/ then :rjust # real number and/or currency
196
+ when /^\$?\s*\d[,\d]*$/ then :rjust # integer
197
+ when /^$/, /^\s*-\s*$/, nil then nil # empty values have no alignment
198
+ else :ljust
199
+ end
200
+ end
201
+ @align[cx] ||= (col ? type : nil)
202
+ @align[cx] = :ljust if type && @align[cx] != type && rx > 0
203
+ end
204
+ end
205
+
206
+ # now format each row
207
+ s = ''
208
+ self.each_with_index do |row, rx|
209
+ s << table_line(rx == 0 ? :top : :middle)
210
+ s << table_data(row)
211
+ end
212
+ s << table_line(:bottom)
213
+ s
214
+ end
215
+
216
+ ##
217
+ # table_line position
218
+ #
219
+ # generate a table line for position (:top, :middle, :bottom)
220
+ #
221
+ def table_line position
222
+ c = @chars
223
+ left, line, mid, right = case position
224
+ when :top then [c[:tlb], c[:tb], c[:tib], c[:trb]]
225
+ when :middle then [c[:lib], c[:ib], c[:mib], c[:rib]]
226
+ when :bottom then [c[:blb], c[:bb], c[:bib], c[:brb]]
227
+ end
228
+ s = @chars.wrap(left + @widths.map{|w| line * (w + 2)}.join(mid) + right) + "\n"
229
+ s
230
+ end
231
+
232
+ ##
233
+ # table_data data
234
+ #
235
+ # generate a data row as part of a table
236
+
237
+ def table_data data
238
+ left, middle, right = [@chars[:ldb], @chars[:idb], @chars[:rdb]]
239
+ a = []
240
+ data.each_with_index do |item, x|
241
+ a << (' ' + item.to_s.send(@align[x] || :ljust, @widths[x]) + ' ')
242
+ end
243
+ s = @chars.wrap(left) + a.join(@chars.wrap(middle)) + @chars.wrap(right) + "\n"
244
+ s
245
+ end
246
+
247
+ end
@@ -0,0 +1,3 @@
1
+ class Array::Formatter
2
+ VERSION = "1.0.1"
3
+ end
@@ -0,0 +1,44 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ $LOAD_PATH.unshift '.', './test', './lib'
4
+
5
+ require 'array/formatter'
6
+ require 'test-helper'
7
+
8
+ class Test_Array_Formatter < MiniTest::Unit::TestCase
9
+
10
+ @@a = [ %w( Company Name Address Phone Email ),
11
+ [ 'New Company', 'First Last', 'Somewhere, US', '123-45-6789', 'user@sample.com' ],
12
+ [ 'Old Company', 'First2 Last2', 'Somewhere else, US', '987-65-4321', 'user2@sample.com' ],
13
+ [ 'No Company', 'First3 Last3', 'Elsewhere ZZ', '763-34-1234', 'user3@sample.com' ]
14
+ ]
15
+
16
+ @@a2 = [ %w( Region State Sales ),
17
+ %w( Northwest WA $2,100,500 ),
18
+ %w( Northwest OR $900,800 ),
19
+ %w( Northeast NY $8,120,000 ),
20
+ %w( Northeast MN $489,500 ),
21
+ %w( Southeast GA $2,111,200 ),
22
+ %w( Southeast FL $9,388,000 ),
23
+ %w( Southwest AZ $7,377,000 ) ]
24
+
25
+
26
+ def test_to_table_default
27
+ s = @@a.to_table
28
+ puts s
29
+ end
30
+
31
+ def test_to_table_unicode
32
+ s = @@a.to_table(:unicode)
33
+ puts s
34
+ end
35
+
36
+ def test_to_table_alignments
37
+ s = @@a2.to_table
38
+ puts s
39
+ puts ''
40
+ s = @@a2.to_table(:unicode)
41
+ puts s
42
+ end
43
+
44
+ end
@@ -0,0 +1,4 @@
1
+ require 'rubygems'
2
+ require 'bundler/setup'
3
+ require 'minitest/autorun'
4
+ require 'array/formatter'
metadata ADDED
@@ -0,0 +1,86 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: array-formatter
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.0.1
5
+ platform: ruby
6
+ authors:
7
+ - Alan Stebbens
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2013-09-17 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: bundler
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ~>
18
+ - !ruby/object:Gem::Version
19
+ version: '1.3'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ~>
25
+ - !ruby/object:Gem::Version
26
+ version: '1.3'
27
+ - !ruby/object:Gem::Dependency
28
+ name: rake
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - '>='
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - '>='
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
41
+ description: |2
42
+ A simple gem to reformat an array of arrays into one of several string
43
+ formats: HTML table; CSV; ASCII table; YAML
44
+ email:
45
+ - aks@stebbens.org
46
+ executables: []
47
+ extensions: []
48
+ extra_rdoc_files: []
49
+ files:
50
+ - .gitignore
51
+ - Gemfile
52
+ - LICENSE.txt
53
+ - README.md
54
+ - Rakefile
55
+ - array-formatter.gemspec
56
+ - lib/array/formatter.rb
57
+ - lib/array/formatter/version.rb
58
+ - test/test-array-formatter.rb
59
+ - test/test-helper.rb
60
+ homepage: https://gitlab.com/as/array-formatter
61
+ licenses:
62
+ - MIT
63
+ metadata: {}
64
+ post_install_message:
65
+ rdoc_options: []
66
+ require_paths:
67
+ - lib
68
+ required_ruby_version: !ruby/object:Gem::Requirement
69
+ requirements:
70
+ - - '>='
71
+ - !ruby/object:Gem::Version
72
+ version: '0'
73
+ required_rubygems_version: !ruby/object:Gem::Requirement
74
+ requirements:
75
+ - - '>='
76
+ - !ruby/object:Gem::Version
77
+ version: '0'
78
+ requirements: []
79
+ rubyforge_project:
80
+ rubygems_version: 2.0.7
81
+ signing_key:
82
+ specification_version: 4
83
+ summary: Format an array of arrays in one of serveral string formats
84
+ test_files:
85
+ - test/test-array-formatter.rb
86
+ - test/test-helper.rb