table_print 0.1.1 → 0.1.2
Sign up to get free protection for your applications and to get access to all the features.
- data/README.rdoc +18 -0
- data/VERSION +1 -1
- data/lib/table_print.rb +52 -25
- data/table_print.gemspec +2 -2
- data/test/test_column.rb +49 -8
- data/test/test_table_print.rb +28 -0
- metadata +4 -4
data/README.rdoc
CHANGED
@@ -46,6 +46,24 @@ on your model.
|
|
46
46
|
If you're not using ActiveRecord, the TablePrint default is to show all the methods on your object. Thus, the <b>:include</b>
|
47
47
|
option is useless at the moment. You are still able to use <b>:only</b> and <b>:include</b>.
|
48
48
|
|
49
|
+
=== Column options
|
50
|
+
|
51
|
+
Pass options to individual columns through the options hash by using the display method as the hash key. Eg, if you wanted
|
52
|
+
to rename the <b>pay_rate</b> column to <b>Special User Payment Teir</b>,
|
53
|
+
|
54
|
+
tp User.all, :pay_rate => {:name => "Special User Payment Teir"}
|
55
|
+
|
56
|
+
Columns have other options, including:
|
57
|
+
|
58
|
+
<b>name</b>: Use this in the column header instead of the name of the display method.
|
59
|
+
|
60
|
+
<b>max_field_length:</b> <i>(default: 30)</i> Field lengths are determined based on the data in the column. Setting your own max
|
61
|
+
will ensure that the column is as skinny as possible, but never above the number you provide.
|
62
|
+
|
63
|
+
<b>field_length:</b> Useful for very large data sets, this option will explicitly set the column width regardless of the data
|
64
|
+
it contains.
|
65
|
+
|
66
|
+
|
49
67
|
== Contributing to table_print
|
50
68
|
|
51
69
|
* Check out the latest master to make sure the feature hasn't been implemented or the bug hasn't been fixed yet
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.1.
|
1
|
+
0.1.2
|
data/lib/table_print.rb
CHANGED
@@ -13,6 +13,16 @@
|
|
13
13
|
|
14
14
|
class TablePrint
|
15
15
|
|
16
|
+
OBJECT_CLASSES = [String, Bignum, Regexp, ThreadError, Numeric, SystemStackError, IndexError,
|
17
|
+
SecurityError, SizedQueue, IO, Range, Object, Exception, NoMethodError, TypeError, Integer, Dir,
|
18
|
+
ZeroDivisionError, Kernel, RegexpError, SystemExit, NotImplementedError, Hash,
|
19
|
+
Interrupt, SyntaxError, Enumerable, Struct, Class, Continuation, IOError, Proc,
|
20
|
+
RangeError, Data, Thread, Array, NoMemoryError, Time, MatchData,
|
21
|
+
ConditionVariable, Method, Mutex, StopIteration, Comparable, ArgumentError, Float,
|
22
|
+
FloatDomainError, UnboundMethod, ThreadGroup, Precision, RuntimeError, FalseClass, Fixnum, Queue,
|
23
|
+
StandardError, EOFError, LoadError, NameError, NilClass, TrueClass, MatchingData,
|
24
|
+
LocalJumpError, Binding, SignalException, SystemCallError, File, ScriptError, Module, Symbol]
|
25
|
+
|
16
26
|
# TODO: make options for things like MAX_FIELD_LENGTH
|
17
27
|
# TODO: make options for things like separator
|
18
28
|
# TODO: make options for things like column order
|
@@ -24,9 +34,6 @@ class TablePrint
|
|
24
34
|
def tp(data, options = {})
|
25
35
|
data = wrap(data).compact
|
26
36
|
|
27
|
-
# TODO: need to do a better job of handling options.
|
28
|
-
options[:column_options] ||= {}
|
29
|
-
|
30
37
|
# nothing to see here
|
31
38
|
if data.empty?
|
32
39
|
return "No data."
|
@@ -45,7 +52,7 @@ class TablePrint
|
|
45
52
|
# TODO: don't check field length on fixed-width columns
|
46
53
|
|
47
54
|
# make columns for all the display methods
|
48
|
-
columns = display_methods.collect { |m| Column.new(data, m, options[
|
55
|
+
columns = display_methods.collect { |m| Column.new(data, m, options[m] || options[m.to_sym]) }
|
49
56
|
|
50
57
|
output = [] # a list of rows. we'll join this with newlines when we're done
|
51
58
|
|
@@ -131,7 +138,13 @@ class TablePrint
|
|
131
138
|
return [] if [Float, Fixnum, String, Numeric, Array, Hash].include? data_obj.class
|
132
139
|
|
133
140
|
# custom class
|
134
|
-
methods = data_obj.class.instance_methods
|
141
|
+
methods = data_obj.class.instance_methods
|
142
|
+
OBJECT_CLASSES.each do |oclass|
|
143
|
+
if data_obj.is_a? oclass
|
144
|
+
methods = methods - oclass.instance_methods # we're only interested in custom methods, not ruby core methods
|
145
|
+
end
|
146
|
+
end
|
147
|
+
|
135
148
|
methods.delete_if { |m| m[-1].chr == "=" } # don't use assignment methods
|
136
149
|
methods.map! { |m| m.to_s } # make any symbols into strings
|
137
150
|
methods
|
@@ -164,12 +177,14 @@ class TablePrint
|
|
164
177
|
attr_accessor :name, :display_method, :options, :data, :field_length, :max_field_length
|
165
178
|
|
166
179
|
def initialize(data, display_method, options = {})
|
167
|
-
options
|
168
|
-
self.data = data # HACK? would rather not keep pointers to the data set all over the place
|
180
|
+
self.options = options || {} # could have been passed an explicit nil
|
169
181
|
self.display_method = display_method
|
170
|
-
self.name = options[:name] || display_method.gsub("_", " ")
|
171
|
-
self.max_field_length = options[:max_field_length] || 30
|
182
|
+
self.name = self.options[:name] || display_method.gsub("_", " ")
|
183
|
+
self.max_field_length = self.options[:max_field_length] || 30
|
172
184
|
self.max_field_length = [self.max_field_length, 1].max # numbers less than one are meaningless
|
185
|
+
|
186
|
+
# initialization
|
187
|
+
self.initialize_field_length(data)
|
173
188
|
end
|
174
189
|
|
175
190
|
def formatted_header
|
@@ -180,24 +195,34 @@ class TablePrint
|
|
180
195
|
"%-#{self.field_length}s" % truncate(data_obj.send(self.display_method).to_s)
|
181
196
|
end
|
182
197
|
|
183
|
-
def
|
184
|
-
|
185
|
-
|
186
|
-
|
187
|
-
|
188
|
-
|
189
|
-
|
190
|
-
|
191
|
-
|
198
|
+
def initialize_field_length(data)
|
199
|
+
# skip all this nonsense if we've been explicitly told what to do
|
200
|
+
if self.options[:field_length] and self.options[:field_length] > 0
|
201
|
+
length = self.options[:field_length]
|
202
|
+
else
|
203
|
+
length = self.name.length # it has to at least be long enough for the column header!
|
204
|
+
|
205
|
+
start = Time.now
|
206
|
+
data.each do |data_obj|
|
207
|
+
next if data_obj.nil?
|
208
|
+
|
209
|
+
# fixed-width fields don't require the full loop
|
210
|
+
case data_obj.send(self.display_method)
|
211
|
+
when Time
|
212
|
+
length = data_obj.send(self.display_method).to_s.length
|
213
|
+
break
|
214
|
+
when TrueClass, FalseClass
|
215
|
+
length = [5, length].max
|
216
|
+
break
|
217
|
+
end
|
218
|
+
|
219
|
+
length = [length, data_obj.send(self.display_method).to_s.length].max
|
220
|
+
break if length >= self.max_field_length # we're never going to longer than the global max, so why keep going
|
221
|
+
break if (Time.now - start) > 2 # assume if we loop for more than 2s that we've made it through a representative sample, and bail
|
222
|
+
end
|
192
223
|
end
|
193
224
|
|
194
|
-
|
195
|
-
self.data.each do |data_obj|
|
196
|
-
length = [length, data_obj.send(self.display_method).to_s.length].max
|
197
|
-
break if length >= self.max_field_length # we're never going to longer than the global max, so why keep going
|
198
|
-
end
|
199
|
-
@field_length = [length, self.max_field_length].min
|
200
|
-
@field_length
|
225
|
+
self.field_length = [length, self.max_field_length].min # never bigger than the max
|
201
226
|
end
|
202
227
|
|
203
228
|
private
|
@@ -223,3 +248,5 @@ module Kernel
|
|
223
248
|
|
224
249
|
module_function :tp
|
225
250
|
end
|
251
|
+
|
252
|
+
|
data/table_print.gemspec
CHANGED
@@ -5,11 +5,11 @@
|
|
5
5
|
|
6
6
|
Gem::Specification.new do |s|
|
7
7
|
s.name = %q{table_print}
|
8
|
-
s.version = "0.1.
|
8
|
+
s.version = "0.1.2"
|
9
9
|
|
10
10
|
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
11
11
|
s.authors = ["Chris Doyle"]
|
12
|
-
s.date = %q{2011-04-
|
12
|
+
s.date = %q{2011-04-17}
|
13
13
|
s.description = %q{TablePrint formats an object or array of objects into columns for easy reading. To do this, it assumes the objects in your array all respond to the same methods (vs pretty_print or awesome_print, who can't create columns because your objects could be entirely different).}
|
14
14
|
s.email = %q{archslide@gmail.com}
|
15
15
|
s.extra_rdoc_files = [
|
data/test/test_column.rb
CHANGED
@@ -17,23 +17,57 @@ class TestTablePrint < Test::Unit::TestCase
|
|
17
17
|
context 'Instantiating a Column' do
|
18
18
|
context 'with a display_method' do
|
19
19
|
setup do
|
20
|
-
@column = TablePrint::Column.new([], "
|
20
|
+
@column = TablePrint::Column.new([], "to_s")
|
21
21
|
end
|
22
22
|
should 'remember the display method' do
|
23
|
-
assert_equal "
|
23
|
+
assert_equal "to_s", @column.display_method
|
24
24
|
end
|
25
25
|
should 'set the name' do
|
26
|
-
assert_equal "
|
26
|
+
assert_equal "to s", @column.name
|
27
27
|
end
|
28
28
|
end
|
29
29
|
|
30
|
-
context 'with
|
31
|
-
|
32
|
-
|
30
|
+
context 'with options including' do
|
31
|
+
context 'name' do
|
32
|
+
setup do
|
33
|
+
@column = TablePrint::Column.new([], "first", {:name => "test_tube"})
|
34
|
+
end
|
35
|
+
|
36
|
+
should 'set the name according to the options' do
|
37
|
+
assert_equal "test_tube", @column.name
|
38
|
+
end
|
33
39
|
end
|
34
40
|
|
35
|
-
|
36
|
-
|
41
|
+
context 'a field_length' do
|
42
|
+
context 'that is valid' do
|
43
|
+
setup do
|
44
|
+
@column = TablePrint::Column.new(["short"], "first", {:field_length => 20})
|
45
|
+
end
|
46
|
+
|
47
|
+
should 'set the field length according to the options' do
|
48
|
+
assert_equal 20, @column.field_length
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
context 'that is less than 1' do
|
53
|
+
setup do
|
54
|
+
@column = TablePrint::Column.new(["short"], "first", {:field_length => 0})
|
55
|
+
end
|
56
|
+
|
57
|
+
should 'ignore the field_length' do
|
58
|
+
assert_equal 5, @column.field_length
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
context 'that is bigger than the max' do
|
63
|
+
setup do
|
64
|
+
@column = TablePrint::Column.new(["short"], "first", {:field_length => 20, :max_field_length => 10})
|
65
|
+
end
|
66
|
+
|
67
|
+
should 'respect the max_field_length' do
|
68
|
+
assert_equal 10, @column.field_length
|
69
|
+
end
|
70
|
+
end
|
37
71
|
end
|
38
72
|
end
|
39
73
|
end
|
@@ -89,6 +123,13 @@ class TestTablePrint < Test::Unit::TestCase
|
|
89
123
|
assert_equal 5, TablePrint::Column.new([[false]], "first", :name => "dur").field_length
|
90
124
|
end
|
91
125
|
end
|
126
|
+
|
127
|
+
context 'when the column is boolean and the data is not the limiting factor' do
|
128
|
+
should 'be the column name length' do
|
129
|
+
assert_equal 7, TablePrint::Column.new([[true]], "unshift").field_length
|
130
|
+
assert_equal 8, TablePrint::Column.new([[false]], "unshift", :name => "durables").field_length
|
131
|
+
end
|
132
|
+
end
|
92
133
|
end
|
93
134
|
|
94
135
|
end
|
data/test/test_table_print.rb
CHANGED
@@ -60,6 +60,18 @@ class ManyMethods
|
|
60
60
|
end
|
61
61
|
end
|
62
62
|
|
63
|
+
class StringInheritor < String
|
64
|
+
attr_accessor :title
|
65
|
+
end
|
66
|
+
|
67
|
+
class ArrayInheritor < Array
|
68
|
+
attr_accessor :title
|
69
|
+
end
|
70
|
+
|
71
|
+
class HashInheritor < Hash
|
72
|
+
attr_accessor :title
|
73
|
+
end
|
74
|
+
|
63
75
|
class TestTablePrint < Test::Unit::TestCase
|
64
76
|
|
65
77
|
# TODO: active record tests if defined?(ActiveRecord)
|
@@ -104,6 +116,22 @@ class TestTablePrint < Test::Unit::TestCase
|
|
104
116
|
should 'only be the attr setter' do
|
105
117
|
assert_equal ["title"], @tp._get_default_display_methods(OneAttrAccessor.new)
|
106
118
|
end
|
119
|
+
|
120
|
+
context 'that subclasses Hash' do
|
121
|
+
should 'only be the attr setter' do
|
122
|
+
assert_equal ["title"], @tp._get_default_display_methods(HashInheritor.new)
|
123
|
+
end
|
124
|
+
end
|
125
|
+
context 'that subclasses Array' do
|
126
|
+
should 'only be the attr setter' do
|
127
|
+
assert_equal ["title"], @tp._get_default_display_methods(ArrayInheritor.new)
|
128
|
+
end
|
129
|
+
end
|
130
|
+
context 'that subclasses String' do
|
131
|
+
should 'only be the attr setter' do
|
132
|
+
assert_equal ["title"], @tp._get_default_display_methods(StringInheritor.new)
|
133
|
+
end
|
134
|
+
end
|
107
135
|
end
|
108
136
|
|
109
137
|
context 'The display methods for a custom class using the :only option' do
|
metadata
CHANGED
@@ -1,13 +1,13 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: table_print
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
hash:
|
4
|
+
hash: 31
|
5
5
|
prerelease:
|
6
6
|
segments:
|
7
7
|
- 0
|
8
8
|
- 1
|
9
|
-
-
|
10
|
-
version: 0.1.
|
9
|
+
- 2
|
10
|
+
version: 0.1.2
|
11
11
|
platform: ruby
|
12
12
|
authors:
|
13
13
|
- Chris Doyle
|
@@ -15,7 +15,7 @@ autorequire:
|
|
15
15
|
bindir: bin
|
16
16
|
cert_chain: []
|
17
17
|
|
18
|
-
date: 2011-04-
|
18
|
+
date: 2011-04-17 00:00:00 -07:00
|
19
19
|
default_executable:
|
20
20
|
dependencies:
|
21
21
|
- !ruby/object:Gem::Dependency
|