table_display 0.5.0
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +5 -0
- data/Gemfile +15 -0
- data/MIT-LICENSE +20 -0
- data/README +82 -0
- data/Rakefile +16 -0
- data/init.rb +15 -0
- data/lib/table_display.rb +105 -0
- data/lib/table_display/version.rb +3 -0
- data/table_display.gemspec +38 -0
- data/test/database.yml +3 -0
- data/test/fixtures/projects.yml +4 -0
- data/test/fixtures/tasks.yml +16 -0
- data/test/schema.rb +15 -0
- data/test/table_display_test.rb +297 -0
- data/test/test_helper.rb +28 -0
- metadata +141 -0
data/.gitignore
ADDED
data/Gemfile
ADDED
@@ -0,0 +1,15 @@
|
|
1
|
+
source "http://rubygems.org"
|
2
|
+
|
3
|
+
# Declare your gem's dependencies in transaction_isolation_level.gemspec.
|
4
|
+
# Bundler will treat runtime dependencies like base dependencies, and
|
5
|
+
# development dependencies will be added by default to the :development group.
|
6
|
+
gemspec
|
7
|
+
|
8
|
+
# Declare any dependencies that are still in development here instead of in
|
9
|
+
# your gemspec. These might include edge Rails or gems from your path or
|
10
|
+
# Git. Remember to move these dependencies to your gemspec before releasing
|
11
|
+
# your gem to rubygems.org.
|
12
|
+
|
13
|
+
# To use debugger
|
14
|
+
# gem 'ruby-debug19', :require => 'ruby-debug'
|
15
|
+
# gem 'ruby-debug'
|
data/MIT-LICENSE
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright (c) 2009 Will Bryant, Sekuda Ltd
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
4
|
+
a copy of this software and associated documentation files (the
|
5
|
+
"Software"), to deal in the Software without restriction, including
|
6
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
7
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to
|
9
|
+
the following conditions:
|
10
|
+
|
11
|
+
The above copyright notice and this permission notice shall be
|
12
|
+
included in all copies or substantial portions of the Software.
|
13
|
+
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
15
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
16
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
17
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
18
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
19
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
20
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README
ADDED
@@ -0,0 +1,82 @@
|
|
1
|
+
Table Display
|
2
|
+
=============
|
3
|
+
|
4
|
+
Adds support for displaying your ActiveRecord tables, named scopes, collections, or
|
5
|
+
plain arrays in a table view when working in rails console, shell, or email template.
|
6
|
+
|
7
|
+
Enumerable#to_table returns the printable strings; Object#pt calls #to_table on its
|
8
|
+
first argument and puts out the result.
|
9
|
+
|
10
|
+
Columns you haven't loaded (eg. from using :select) are omitted, and derived/calculated
|
11
|
+
columns (eg. again, from using :select) are added.
|
12
|
+
|
13
|
+
Both #to_table and Object#pt methods take :only, :except, and :methods which work like
|
14
|
+
the #to_xml method to change what attributes/methods are output.
|
15
|
+
|
16
|
+
The normal output uses #inspect on the data values to make them printable, so you can
|
17
|
+
see what type the values had. When that's inconvenient or you'd prefer direct display,
|
18
|
+
you can pass the option :inspect => false to disable inspection.
|
19
|
+
|
20
|
+
|
21
|
+
Example
|
22
|
+
=======
|
23
|
+
|
24
|
+
# You can call the to_table method:
|
25
|
+
>> puts Project.find(31).tasks.to_table
|
26
|
+
+----+------------+------------------------+------------------+--------------------------------+--------------------------------+--------------------------------+
|
27
|
+
| id | project_id | description | due_on | completed_at | created_at | updated_at |
|
28
|
+
+----+------------+------------------------+------------------+--------------------------------+--------------------------------+--------------------------------+
|
29
|
+
| 1 | 31 | "Write a handy plugin" | Wed, 25 Mar 2009 | Tue Mar 24 23:17:05 +1300 2009 | Mon Mar 23 09:11:02 +1300 2009 | Tue Mar 24 23:17:05 +1300 2009 |
|
30
|
+
| 2 | 31 | "Blog the plugin" | Sun, 05 Apr 2009 | nil | Mon Mar 23 09:11:46 +1300 2009 | Mon Mar 23 09:11:46 +1300 2009 |
|
31
|
+
+----+------------+------------------------+------------------+--------------------------------+--------------------------------+--------------------------------+
|
32
|
+
|
33
|
+
# Or equivalently, use "pt" (like pp, but in a table):
|
34
|
+
>> pt Customer.find(31).purchases
|
35
|
+
+----+------------+------------------------+------------------+--------------------------------+--------------------------------+--------------------------------+
|
36
|
+
| id | project_id | description | due_on | completed_at | created_at | updated_at |
|
37
|
+
+----+------------+------------------------+------------------+--------------------------------+--------------------------------+--------------------------------+
|
38
|
+
| 1 | 31 | "Write a handy plugin" | Wed, 25 Mar 2009 | Tue Mar 24 23:17:05 +1300 2009 | Mon Mar 23 09:11:02 +1300 2009 | Tue Mar 24 23:17:05 +1300 2009 |
|
39
|
+
| 2 | 31 | "Blog the plugin" | Sun, 05 Apr 2009 | nil | Mon Mar 23 09:11:46 +1300 2009 | Mon Mar 23 09:11:46 +1300 2009 |
|
40
|
+
+----+------------+------------------------+------------------+--------------------------------+--------------------------------+--------------------------------+
|
41
|
+
|
42
|
+
|
43
|
+
# Like to_xml, you can pass a :methods option to add the output methods on your models, and you can pass :only or :except
|
44
|
+
# to (respectively) show only certain columns or show all except certain columns:
|
45
|
+
>> puts Customer.find(31).purchases.to_table(:only => [:id, :description], :methods => [:met_due_date?])
|
46
|
+
+----+------------------------+---------------+
|
47
|
+
| id | description | met_due_date? |
|
48
|
+
+----+------------------------+---------------+
|
49
|
+
| 1 | "Write a handy plugin" | true |
|
50
|
+
| 2 | "Blog the plugin" | nil |
|
51
|
+
+----+------------------------+---------------+
|
52
|
+
|
53
|
+
# pt accepts and passes on all options as well:
|
54
|
+
>> pt Customer.find(31).purchases, :only => [:id, :description], :methods => [:met_due_date?]
|
55
|
+
+----+------------------------+---------------+
|
56
|
+
| id | description | met_due_date? |
|
57
|
+
+----+------------------------+---------------+
|
58
|
+
| 1 | "Write a handy plugin" | true |
|
59
|
+
| 2 | "Blog the plugin" | nil |
|
60
|
+
+----+------------------------+---------------+
|
61
|
+
|
62
|
+
# There's a convenient equivalent syntax for displaying an ordered list of columns, like :only and :methods:
|
63
|
+
>> puts Customer.find(31).purchases.to_table :id, :description, :met_due_date?
|
64
|
+
# which provides:
|
65
|
+
>> pt Customer.find(31).purchases, :id, :description, :met_due_date?
|
66
|
+
# resulting in the same output as above.
|
67
|
+
|
68
|
+
|
69
|
+
# If :inspect => false is used, the values will be shown in #to_s form rather than #inspect form:
|
70
|
+
>> pt Customer.find(31).purchases, :only => [:id, :description, :due_on, :completed_at]
|
71
|
+
+----+----------------------+------------+--------------------------------+
|
72
|
+
| id | description | due_on | completed_at |
|
73
|
+
+----+----------------------+------------+--------------------------------+
|
74
|
+
| 1 | Write a handy plugin | 2009-03-25 | Tue Mar 24 23:17:05 +1300 2009 |
|
75
|
+
| 2 | Blog the plugin | 2009-04-05 | |
|
76
|
+
+----+----------------------+------------+--------------------------------+
|
77
|
+
|
78
|
+
|
79
|
+
# Note that in all cases, values descending from Numeric are right-aligned, while all other values are left-aligned.
|
80
|
+
|
81
|
+
|
82
|
+
Copyright (c) 2009 Will Bryant, Sekuda Ltd, released under the MIT license
|
data/Rakefile
ADDED
@@ -0,0 +1,16 @@
|
|
1
|
+
#!/usr/bin/env rake
|
2
|
+
|
3
|
+
require 'bundler/gem_tasks'
|
4
|
+
require 'rake'
|
5
|
+
require 'rake/testtask'
|
6
|
+
|
7
|
+
desc 'Default: run unit tests.'
|
8
|
+
task :default => :test
|
9
|
+
|
10
|
+
desc 'Test the table_display plugin.'
|
11
|
+
Rake::TestTask.new(:test) do |t|
|
12
|
+
t.libs << 'lib'
|
13
|
+
t.libs << 'test'
|
14
|
+
t.pattern = 'test/*_test.rb'
|
15
|
+
t.verbose = true
|
16
|
+
end
|
data/init.rb
ADDED
@@ -0,0 +1,15 @@
|
|
1
|
+
require 'table_display'
|
2
|
+
|
3
|
+
# all Enumerable classes should get TableDisplay functionality...
|
4
|
+
Enumerable.send(:include, TableDisplay)
|
5
|
+
|
6
|
+
# including those that have already included Enumerable by the time this plugin is loaded.
|
7
|
+
# Ruby doesn't recursively update through the module tree, so although any new classes/modules
|
8
|
+
# that include Enumerable will get TableDisplay, we have to do it ourself for older ones.
|
9
|
+
ObjectSpace.each_object(Module) {|o| o.send(:include, TableDisplay) if o.ancestors.include?(Enumerable)}
|
10
|
+
ObjectSpace.each_object(Class) {|o| o.send(:include, TableDisplay) if o.ancestors.include?(Enumerable)}
|
11
|
+
|
12
|
+
# Rails 2.3 named_scopes certainly quack like enumerables, but surprisingly they don't themself include Enumerable.
|
13
|
+
if ActiveRecord.const_defined?(:NamedScope) && ActiveRecord::NamedScope.const_defined?(:Scope)
|
14
|
+
ActiveRecord::NamedScope::Scope.send(:include, TableDisplay)
|
15
|
+
end
|
@@ -0,0 +1,105 @@
|
|
1
|
+
module TableDisplay
|
2
|
+
def to_table(*args)
|
3
|
+
options = args.last.is_a?(Hash) ? args.pop : {}
|
4
|
+
extra_methods = args.length > 0 ? args.collect(&:to_s) : []
|
5
|
+
extra_methods += Array(options.delete(:methods)) if options[:methods]
|
6
|
+
only_attributes = Array(options.delete(:only)) if options[:only]
|
7
|
+
only_attributes ||= [] if args.length > 0
|
8
|
+
except_attributes = Array(options.delete(:except)) if options[:except]
|
9
|
+
except_attributes = (except_attributes + except_attributes.collect(&:to_s)).uniq if except_attributes.present? # we have to keep string and symbol arguments separate for hashes, which may not have 'indifferent access'
|
10
|
+
display_inspect = options.nil? || !options.has_key?(:inspect) || options.delete(:inspect)
|
11
|
+
raise "unknown options passed to to_table: #{options.keys.to_sentence}" unless options.blank?
|
12
|
+
|
13
|
+
column_lengths = ActiveSupport::OrderedHash.new
|
14
|
+
|
15
|
+
data = []
|
16
|
+
if only_attributes
|
17
|
+
# we've been given an explicit list of attributes to display
|
18
|
+
only_attributes.each {|attribute| column_lengths[attribute] = 0}
|
19
|
+
else
|
20
|
+
# find all the attribute names
|
21
|
+
each do |record|
|
22
|
+
next if record.nil?
|
23
|
+
|
24
|
+
# ActiveRecord's #attributes implementation iterates over #attribute_names adding a duped value to the output hash for each entry, so
|
25
|
+
# it's actually more expensive to get the keys and values in one go using #attributes than it is for us to work off #attribute_names ourselves.
|
26
|
+
if record.respond_to?(:attribute_names)
|
27
|
+
# an ActiveModel instance
|
28
|
+
attribute_names = record.attribute_names
|
29
|
+
elsif Object.const_defined?(:OpenStruct) && record.is_a?(OpenStruct)
|
30
|
+
# OpenStruct has a crappy API, #inspect will show the attributes but there's no public way to get a list of them!
|
31
|
+
record = record.instance_variable_get("@table")
|
32
|
+
attribute_names = record.keys
|
33
|
+
elsif record.respond_to?(:attributes)
|
34
|
+
# something like an ActiveResource, which doesn't implement attribute_names but does implement attributes
|
35
|
+
attribute_names = record.attributes.keys
|
36
|
+
else
|
37
|
+
# hopefully something like a hash
|
38
|
+
attribute_names = record.keys
|
39
|
+
end
|
40
|
+
|
41
|
+
if attribute_names.any? {|name| column_lengths[name].nil?} # optimisation, in most use cases all records will have the same type and the same attributes, so we needn't run this for each - but we do handle varying attribute lists, and attributes that are not columns on the model (calculated columns etc.)
|
42
|
+
# for ActiveRecord classes, we look at the .columns explicitly so we can keep them in the right order
|
43
|
+
columns_to_check = record.is_a?(ActiveRecord::Base) ? ((record.class.columns.collect(&:name) & attribute_names) + attribute_names).uniq : attribute_names
|
44
|
+
columns_to_check.each do |name|
|
45
|
+
next if (only_attributes && !only_attributes.include?(name)) || (except_attributes && except_attributes.include?(name))
|
46
|
+
column_lengths[name] = 0 # the values of columns are the maximum width of value seen; when we come to print out, if the max seen is zero then the attribute has never actually been seen (eg. when a find(:all, :select => ...) has been used to exclude some of the database columns from the resultset), and we hide the column.
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
# also add any :methods given to the list
|
53
|
+
extra_methods.each {|name| column_lengths[name] = 0}
|
54
|
+
|
55
|
+
each do |record|
|
56
|
+
# add the values for all the columns in our list in order they are
|
57
|
+
data << column_lengths.collect do |attribute, max_width|
|
58
|
+
value = record.is_a?(Hash) ? record[attribute] : record.send(attribute)
|
59
|
+
string_value = display_inspect ? value.inspect : (value.is_a?(String) ? value : value.to_s)
|
60
|
+
column_lengths[attribute] = string_value.mb_chars.length if string_value.mb_chars.length > max_width
|
61
|
+
value.is_a?(Numeric) ? value : string_value # keep Numeric values as-is for now, so we can handle them specially in the output below
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
return [] if data.empty?
|
66
|
+
|
67
|
+
# build the table header
|
68
|
+
separator_string = "+"
|
69
|
+
heading_string = "|"
|
70
|
+
column_lengths.each do |attribute, max_width|
|
71
|
+
next unless max_width > 0 # skip any columns we never actually saw
|
72
|
+
name = attribute.to_s
|
73
|
+
|
74
|
+
# the column needs to fit the column header as well as the values
|
75
|
+
if name.mb_chars.length > max_width
|
76
|
+
column_lengths[attribute] = max_width = name.mb_chars.length
|
77
|
+
end
|
78
|
+
|
79
|
+
separator_string << '-'*(max_width + 2) << '+'
|
80
|
+
heading_string << ' ' << name.ljust(max_width) << ' |'
|
81
|
+
end
|
82
|
+
|
83
|
+
rows = [separator_string, heading_string, separator_string]
|
84
|
+
data.each do |data_row|
|
85
|
+
data_string = "|"
|
86
|
+
column_lengths.each_with_index do |(attribute, max_width), index|
|
87
|
+
next unless max_width > 0 # skip any columns we never actually saw
|
88
|
+
value = data_row[index]
|
89
|
+
if value.is_a?(Numeric)
|
90
|
+
data_string << ' ' << (display_inspect ? value.inspect : value.to_s).mb_chars.rjust(max_width) << ' |'
|
91
|
+
else
|
92
|
+
data_string << ' ' << value.mb_chars.ljust(max_width) << ' |'
|
93
|
+
end
|
94
|
+
end
|
95
|
+
rows << data_string
|
96
|
+
end
|
97
|
+
rows << separator_string
|
98
|
+
end
|
99
|
+
end
|
100
|
+
|
101
|
+
module Kernel
|
102
|
+
def pt(target, *options)
|
103
|
+
puts target.to_table(*options)
|
104
|
+
end
|
105
|
+
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
require File.expand_path('../lib/table_display/version', __FILE__)
|
3
|
+
|
4
|
+
spec = Gem::Specification.new do |gem|
|
5
|
+
gem.name = 'table_display'
|
6
|
+
gem.version = TableDisplay::VERSION
|
7
|
+
gem.summary = "Adds support for displaying your ActiveRecord tables, named scopes, collections, or plain arrays in a table view when working in script/console, shell, or email template."
|
8
|
+
gem.description = <<-EOF
|
9
|
+
Adds support for displaying your ActiveRecord tables, named scopes, collections, or
|
10
|
+
plain arrays in a table view when working in rails console, shell, or email template.
|
11
|
+
|
12
|
+
Enumerable#to_table returns the printable strings; Object#pt calls #to_table on its
|
13
|
+
first argument and puts out the result.
|
14
|
+
|
15
|
+
Columns you haven't loaded (eg. from using :select) are omitted, and derived/calculated
|
16
|
+
columns (eg. again, from using :select) are added.
|
17
|
+
|
18
|
+
Both #to_table and Object#pt methods take :only, :except, and :methods which work like
|
19
|
+
the #to_xml method to change what attributes/methods are output.
|
20
|
+
|
21
|
+
The normal output uses #inspect on the data values to make them printable, so you can
|
22
|
+
see what type the values had. When that's inconvenient or you'd prefer direct display,
|
23
|
+
you can pass the option :inspect => false to disable inspection.
|
24
|
+
EOF
|
25
|
+
gem.has_rdoc = false
|
26
|
+
gem.author = "Will Bryant"
|
27
|
+
gem.email = "will.bryant@gmail.com"
|
28
|
+
gem.homepage = "http://github.com/willbryant/table_display"
|
29
|
+
|
30
|
+
gem.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
|
31
|
+
gem.files = `git ls-files`.split("\n")
|
32
|
+
gem.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
33
|
+
gem.require_path = "lib"
|
34
|
+
|
35
|
+
gem.add_development_dependency "rake"
|
36
|
+
gem.add_development_dependency "sqlite3"
|
37
|
+
gem.add_development_dependency "activerecord"
|
38
|
+
end
|
data/test/database.yml
ADDED
@@ -0,0 +1,16 @@
|
|
1
|
+
write_a_handy_plugin:
|
2
|
+
id: 1
|
3
|
+
project_id: 31
|
4
|
+
description: "Write a handy plugin"
|
5
|
+
due_on: 2009-03-25
|
6
|
+
completed_at: 2009-03-24 23:17:05
|
7
|
+
created_at: 2009-03-23 09:11:02
|
8
|
+
updated_at: 2009-03-24 23:17:05
|
9
|
+
|
10
|
+
blog_the_plugin:
|
11
|
+
id: 2
|
12
|
+
project_id: 31
|
13
|
+
description: "Blog the plugin"
|
14
|
+
due_on: 2009-04-05
|
15
|
+
created_at: 2009-03-23 09:11:46
|
16
|
+
updated_at: 2009-03-23 09:11:46
|
data/test/schema.rb
ADDED
@@ -0,0 +1,15 @@
|
|
1
|
+
ActiveRecord::Schema.define(:version => 0) do
|
2
|
+
create_table :projects, :force => true do |t|
|
3
|
+
t.string :name, :null => false
|
4
|
+
t.text :description
|
5
|
+
t.timestamps
|
6
|
+
end
|
7
|
+
|
8
|
+
create_table :tasks, :force => true do |t|
|
9
|
+
t.integer :project_id, :null => false
|
10
|
+
t.string :description, :null => false
|
11
|
+
t.date :due_on
|
12
|
+
t.datetime :completed_at
|
13
|
+
t.timestamps
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,297 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
require File.expand_path(File.join(File.dirname(__FILE__), 'test_helper'))
|
3
|
+
require File.expand_path(File.join(File.dirname(__FILE__), 'schema'))
|
4
|
+
require 'ostruct'
|
5
|
+
|
6
|
+
class Time
|
7
|
+
def to_s(*args)
|
8
|
+
return to_formatted_s(*args) unless args.empty?
|
9
|
+
strftime("%Y-%m-%d %H:%M:%S %z")
|
10
|
+
end
|
11
|
+
|
12
|
+
def inspect
|
13
|
+
to_s
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
class Project < ActiveRecord::Base
|
18
|
+
has_many :tasks
|
19
|
+
end
|
20
|
+
|
21
|
+
class Task < ActiveRecord::Base
|
22
|
+
belongs_to :project
|
23
|
+
|
24
|
+
scope :completed, :conditions => 'completed_at IS NOT NULL'
|
25
|
+
|
26
|
+
def completed?
|
27
|
+
!completed_at.nil?
|
28
|
+
end
|
29
|
+
|
30
|
+
def project_name
|
31
|
+
project.name
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
class TableDisplayTest < ActiveSupport::TestCase
|
36
|
+
fixtures :all
|
37
|
+
|
38
|
+
def setup
|
39
|
+
@project = projects(:this_project)
|
40
|
+
end
|
41
|
+
|
42
|
+
test "#to_table is available on arrays" do
|
43
|
+
assert_nothing_raised do
|
44
|
+
[].to_table
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
test "#to_table is available on ActiveRecord find results" do # which should be arrays, in fact
|
49
|
+
assert_nothing_raised do
|
50
|
+
Task.find(:all).to_table
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
test "#to_table is available on ActiveRecord named_scopes" do
|
55
|
+
assert_nothing_raised do
|
56
|
+
Task.completed.to_table
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
test "#to_table is available on ActiveRecord association collections" do
|
61
|
+
assert_nothing_raised do
|
62
|
+
@project.tasks.to_table
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
test "#to_table is available on named scopes in ActiveRecord association collections" do
|
67
|
+
assert_nothing_raised do
|
68
|
+
@project.tasks.completed.to_table
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
# we run some simple regression tests to check that everything works as expected
|
73
|
+
|
74
|
+
test "#to_table by default includes all the database columns in database order" do
|
75
|
+
assert_equal <<END.strip, @project.tasks.to_table.join("\n")
|
76
|
+
+----+------------+------------------------+------------------+---------------------------+---------------------------+---------------------------+
|
77
|
+
| id | project_id | description | due_on | completed_at | created_at | updated_at |
|
78
|
+
+----+------------+------------------------+------------------+---------------------------+---------------------------+---------------------------+
|
79
|
+
| 1 | 31 | "Write a handy plugin" | Wed, 25 Mar 2009 | 2009-03-24 23:17:05 +1300 | 2009-03-23 09:11:02 +1300 | 2009-03-24 23:17:05 +1300 |
|
80
|
+
| 2 | 31 | "Blog the plugin" | Sun, 05 Apr 2009 | nil | 2009-03-23 09:11:46 +1300 | 2009-03-23 09:11:46 +1300 |
|
81
|
+
+----+------------+------------------------+------------------+---------------------------+---------------------------+---------------------------+
|
82
|
+
END
|
83
|
+
end
|
84
|
+
|
85
|
+
test "#to_table by default includes all the database columns in database order even when not called on a typeless array" do
|
86
|
+
assert_equal <<END.strip, @project.tasks.find(:all).to_table.join("\n")
|
87
|
+
+----+------------+------------------------+------------------+---------------------------+---------------------------+---------------------------+
|
88
|
+
| id | project_id | description | due_on | completed_at | created_at | updated_at |
|
89
|
+
+----+------------+------------------------+------------------+---------------------------+---------------------------+---------------------------+
|
90
|
+
| 1 | 31 | "Write a handy plugin" | Wed, 25 Mar 2009 | 2009-03-24 23:17:05 +1300 | 2009-03-23 09:11:02 +1300 | 2009-03-24 23:17:05 +1300 |
|
91
|
+
| 2 | 31 | "Blog the plugin" | Sun, 05 Apr 2009 | nil | 2009-03-23 09:11:46 +1300 | 2009-03-23 09:11:46 +1300 |
|
92
|
+
+----+------------+------------------------+------------------+---------------------------+---------------------------+---------------------------+
|
93
|
+
END
|
94
|
+
end
|
95
|
+
|
96
|
+
test "#to_table leaves out any attributes not loaded" do
|
97
|
+
assert_equal <<END.strip, @project.tasks.find(:all, :select => "id, project_id, completed_at").to_table.join("\n")
|
98
|
+
+----+------------+---------------------------+
|
99
|
+
| id | project_id | completed_at |
|
100
|
+
+----+------------+---------------------------+
|
101
|
+
| 1 | 31 | 2009-03-24 23:17:05 +1300 |
|
102
|
+
| 2 | 31 | nil |
|
103
|
+
+----+------------+---------------------------+
|
104
|
+
END
|
105
|
+
end
|
106
|
+
|
107
|
+
test "#to_table also shows any attributes that are not columns on the underlying table" do
|
108
|
+
assert_equal <<END.strip, @project.tasks.find(:all, :joins => :project, :select => "tasks.id, project_id, projects.description AS BigProjectDescription").to_table.join("\n")
|
109
|
+
+----+------------+-----------------------------------------------------------------------------------------------------+
|
110
|
+
| id | project_id | BigProjectDescription |
|
111
|
+
+----+------------+-----------------------------------------------------------------------------------------------------+
|
112
|
+
| 1 | 31 | "A handy plugin for displaying sets of records in a table format, for easy reading at the console." |
|
113
|
+
| 2 | 31 | "A handy plugin for displaying sets of records in a table format, for easy reading at the console." |
|
114
|
+
+----+------------+-----------------------------------------------------------------------------------------------------+
|
115
|
+
END
|
116
|
+
end
|
117
|
+
|
118
|
+
test "#to_table excludes any columns named in :except" do
|
119
|
+
assert_equal <<END.strip, @project.tasks.to_table(:except => ['created_at', :completed_at]).join("\n")
|
120
|
+
+----+------------+------------------------+------------------+---------------------------+
|
121
|
+
| id | project_id | description | due_on | updated_at |
|
122
|
+
+----+------------+------------------------+------------------+---------------------------+
|
123
|
+
| 1 | 31 | "Write a handy plugin" | Wed, 25 Mar 2009 | 2009-03-24 23:17:05 +1300 |
|
124
|
+
| 2 | 31 | "Blog the plugin" | Sun, 05 Apr 2009 | 2009-03-23 09:11:46 +1300 |
|
125
|
+
+----+------------+------------------------+------------------+---------------------------+
|
126
|
+
END
|
127
|
+
end
|
128
|
+
|
129
|
+
test "#to_table excludes all columns except those named in :only" do
|
130
|
+
assert_equal <<END.strip, @project.tasks.to_table(:only => ['id', :due_on]).join("\n")
|
131
|
+
+----+------------------+
|
132
|
+
| id | due_on |
|
133
|
+
+----+------------------+
|
134
|
+
| 1 | Wed, 25 Mar 2009 |
|
135
|
+
| 2 | Sun, 05 Apr 2009 |
|
136
|
+
+----+------------------+
|
137
|
+
END
|
138
|
+
end
|
139
|
+
|
140
|
+
test "#to_table keeps the columns in the order given in :only" do
|
141
|
+
assert_equal <<END.strip, @project.tasks.to_table(:only => [:due_on, 'id']).join("\n")
|
142
|
+
+------------------+----+
|
143
|
+
| due_on | id |
|
144
|
+
+------------------+----+
|
145
|
+
| Wed, 25 Mar 2009 | 1 |
|
146
|
+
| Sun, 05 Apr 2009 | 2 |
|
147
|
+
+------------------+----+
|
148
|
+
END
|
149
|
+
assert_equal <<END.strip, @project.tasks.to_table(:only => [:due_on, :id]).join("\n")
|
150
|
+
+------------------+----+
|
151
|
+
| due_on | id |
|
152
|
+
+------------------+----+
|
153
|
+
| Wed, 25 Mar 2009 | 1 |
|
154
|
+
| Sun, 05 Apr 2009 | 2 |
|
155
|
+
+------------------+----+
|
156
|
+
END
|
157
|
+
end
|
158
|
+
|
159
|
+
test "#to_table accepts an unnamed list of arguments for column names" do
|
160
|
+
assert_equal <<END.strip, @project.tasks.to_table('id', :due_on, :completed?).join("\n")
|
161
|
+
+----+------------------+------------+
|
162
|
+
| id | due_on | completed? |
|
163
|
+
+----+------------------+------------+
|
164
|
+
| 1 | Wed, 25 Mar 2009 | true |
|
165
|
+
| 2 | Sun, 05 Apr 2009 | false |
|
166
|
+
+----+------------------+------------+
|
167
|
+
END
|
168
|
+
end
|
169
|
+
|
170
|
+
test "#to_table allows auxiliary named arguments with the array format" do
|
171
|
+
assert_equal <<END.strip, @project.tasks.to_table('id', :due_on, :completed?, :inspect => false).join("\n")
|
172
|
+
+----+------------+------------+
|
173
|
+
| id | due_on | completed? |
|
174
|
+
+----+------------+------------+
|
175
|
+
| 1 | 2009-03-25 | true |
|
176
|
+
| 2 | 2009-04-05 | false |
|
177
|
+
+----+------------+------------+
|
178
|
+
END
|
179
|
+
end
|
180
|
+
|
181
|
+
test "#to_table also shows any :methods given as columns" do
|
182
|
+
assert_equal <<END.strip, @project.tasks.to_table(:methods => [:completed?, 'project_name']).join("\n")
|
183
|
+
+----+------------+------------------------+------------------+---------------------------+---------------------------+---------------------------+------------+------------------------+
|
184
|
+
| id | project_id | description | due_on | completed_at | created_at | updated_at | completed? | project_name |
|
185
|
+
+----+------------+------------------------+------------------+---------------------------+---------------------------+---------------------------+------------+------------------------+
|
186
|
+
| 1 | 31 | "Write a handy plugin" | Wed, 25 Mar 2009 | 2009-03-24 23:17:05 +1300 | 2009-03-23 09:11:02 +1300 | 2009-03-24 23:17:05 +1300 | true | "table_display plugin" |
|
187
|
+
| 2 | 31 | "Blog the plugin" | Sun, 05 Apr 2009 | nil | 2009-03-23 09:11:46 +1300 | 2009-03-23 09:11:46 +1300 | false | "table_display plugin" |
|
188
|
+
+----+------------+------------------------+------------------+---------------------------+---------------------------+---------------------------+------------+------------------------+
|
189
|
+
END
|
190
|
+
end
|
191
|
+
|
192
|
+
test "#to_table shows the #to_s format rather than the #inspect format when :inspect => false is set" do
|
193
|
+
assert_equal <<END.strip, @project.tasks.to_table(:inspect => false).join("\n")
|
194
|
+
+----+------------+----------------------+------------+---------------------------+---------------------------+---------------------------+
|
195
|
+
| id | project_id | description | due_on | completed_at | created_at | updated_at |
|
196
|
+
+----+------------+----------------------+------------+---------------------------+---------------------------+---------------------------+
|
197
|
+
| 1 | 31 | Write a handy plugin | 2009-03-25 | 2009-03-24 23:17:05 +1300 | 2009-03-23 09:11:02 +1300 | 2009-03-24 23:17:05 +1300 |
|
198
|
+
| 2 | 31 | Blog the plugin | 2009-04-05 | | 2009-03-23 09:11:46 +1300 | 2009-03-23 09:11:46 +1300 |
|
199
|
+
+----+------------+----------------------+------------+---------------------------+---------------------------+---------------------------+
|
200
|
+
END
|
201
|
+
# note the strings no longer have quotes, the nil is not shown, and the date format happens to be different
|
202
|
+
end
|
203
|
+
|
204
|
+
test "#to_table correctly pads out to match the length in characters of long values with utf-8 sequences" do
|
205
|
+
tasks(:write_a_handy_plugin).update_attribute(:description, "Write a handy plugin \342\200\223 with UTF-8 handling")
|
206
|
+
assert_equal <<END.strip, @project.tasks.to_table(:only => [:id, :description], :inspect => false).join("\n")
|
207
|
+
+----+--------------------------------------------+
|
208
|
+
| id | description |
|
209
|
+
+----+--------------------------------------------+
|
210
|
+
| 1 | Write a handy plugin – with UTF-8 handling |
|
211
|
+
| 2 | Blog the plugin |
|
212
|
+
+----+--------------------------------------------+
|
213
|
+
END
|
214
|
+
end
|
215
|
+
|
216
|
+
test "#to_table correctly pads out short values with utf-8 sequences" do
|
217
|
+
tasks(:blog_the_plugin).update_attribute(:description, "Blog \342\200\223 plugin")
|
218
|
+
assert_equal <<END.strip, @project.tasks.to_table(:only => [:id, :description], :inspect => false).join("\n")
|
219
|
+
+----+----------------------+
|
220
|
+
| id | description |
|
221
|
+
+----+----------------------+
|
222
|
+
| 1 | Write a handy plugin |
|
223
|
+
| 2 | Blog – plugin |
|
224
|
+
+----+----------------------+
|
225
|
+
END
|
226
|
+
end
|
227
|
+
|
228
|
+
test "#to_table on an empty array returns an empty result" do
|
229
|
+
assert_equal [], [].to_table
|
230
|
+
end
|
231
|
+
|
232
|
+
test "#to_table can extract data out of raw hashes" do
|
233
|
+
@records = [{:foo => 1234, :bar => "test"},
|
234
|
+
{:bar => "text", :baz => 5678}]
|
235
|
+
results = @records.to_table.join("\n")
|
236
|
+
assert results.include?('| foo |')
|
237
|
+
assert results.include?('| bar |')
|
238
|
+
assert results.include?('| baz |')
|
239
|
+
assert_equal <<END.strip, @records.to_table(:only => [:foo, :bar, :baz]).join("\n")
|
240
|
+
+------+--------+------+
|
241
|
+
| foo | bar | baz |
|
242
|
+
+------+--------+------+
|
243
|
+
| 1234 | "test" | nil |
|
244
|
+
| nil | "text" | 5678 |
|
245
|
+
+------+--------+------+
|
246
|
+
END
|
247
|
+
assert_equal <<END.strip, @records.to_table(:only => [:bar, :baz]).join("\n")
|
248
|
+
+--------+------+
|
249
|
+
| bar | baz |
|
250
|
+
+--------+------+
|
251
|
+
| "test" | nil |
|
252
|
+
| "text" | 5678 |
|
253
|
+
+--------+------+
|
254
|
+
END
|
255
|
+
assert_equal <<END.strip, @records.to_table(:except => [:bar]).join("\n")
|
256
|
+
+------+------+
|
257
|
+
| foo | baz |
|
258
|
+
+------+------+
|
259
|
+
| 1234 | nil |
|
260
|
+
| nil | 5678 |
|
261
|
+
+------+------+
|
262
|
+
END
|
263
|
+
end
|
264
|
+
|
265
|
+
test "#to_table can extract data out of OpenStruct records" do
|
266
|
+
@records = [OpenStruct.new(:foo => 1234, :bar => "test"),
|
267
|
+
OpenStruct.new(:bar => "text", :baz => 5678)]
|
268
|
+
results = @records.to_table.join("\n")
|
269
|
+
assert results.include?('| foo |')
|
270
|
+
assert results.include?('| bar |')
|
271
|
+
assert results.include?('| baz |')
|
272
|
+
assert_equal <<END.strip, @records.to_table(:only => [:foo, :bar, :baz]).join("\n")
|
273
|
+
+------+--------+------+
|
274
|
+
| foo | bar | baz |
|
275
|
+
+------+--------+------+
|
276
|
+
| 1234 | "test" | nil |
|
277
|
+
| nil | "text" | 5678 |
|
278
|
+
+------+--------+------+
|
279
|
+
END
|
280
|
+
assert_equal <<END.strip, @records.to_table(:only => [:bar, :baz]).join("\n")
|
281
|
+
+--------+------+
|
282
|
+
| bar | baz |
|
283
|
+
+--------+------+
|
284
|
+
| "test" | nil |
|
285
|
+
| "text" | 5678 |
|
286
|
+
+--------+------+
|
287
|
+
END
|
288
|
+
assert_equal <<END.strip, @records.to_table(:except => [:bar]).join("\n")
|
289
|
+
+------+------+
|
290
|
+
| foo | baz |
|
291
|
+
+------+------+
|
292
|
+
| 1234 | nil |
|
293
|
+
| nil | 5678 |
|
294
|
+
+------+------+
|
295
|
+
END
|
296
|
+
end
|
297
|
+
end
|
data/test/test_helper.rb
ADDED
@@ -0,0 +1,28 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require "../../../config/boot.rb" if File.exist?("../../../config/boot.rb")
|
3
|
+
|
4
|
+
$KCODE = 'u' if RUBY_VERSION < '1.9' # as per railties initializer.rb: set unicode mode for Ruby 1.8 (Ruby 1.9 just works)
|
5
|
+
|
6
|
+
require 'test/unit'
|
7
|
+
require 'active_support'
|
8
|
+
require 'active_support/test_case'
|
9
|
+
require 'active_record'
|
10
|
+
require 'active_record/fixtures'
|
11
|
+
|
12
|
+
begin
|
13
|
+
require 'ruby-debug'
|
14
|
+
Debugger.start
|
15
|
+
rescue LoadError
|
16
|
+
# ruby-debug not installed, no debugging for you
|
17
|
+
end
|
18
|
+
|
19
|
+
ENV['RAILS_ENV'] ||= 'test'
|
20
|
+
FileUtils.mkdir File.join(File.dirname(__FILE__), "log") rescue nil
|
21
|
+
RAILS_DEFAULT_LOGGER = ActiveRecord::Base.logger = Logger.new(File.join(File.dirname(__FILE__), "log", "#{ENV['RAILS_ENV']}.log"))
|
22
|
+
|
23
|
+
ActiveRecord::Base.configurations = YAML::load(IO.read(File.join(File.dirname(__FILE__), "database.yml")))
|
24
|
+
ActiveRecord::Base.establish_connection ActiveRecord::Base.configurations[ENV['RAILS_ENV']]
|
25
|
+
ActiveSupport::TestCase.send(:include, ActiveRecord::TestFixtures) if ActiveRecord.const_defined?('TestFixtures')
|
26
|
+
ActiveSupport::TestCase.fixture_path = File.join(File.dirname(__FILE__), "fixtures")
|
27
|
+
|
28
|
+
require File.expand_path(File.join(File.dirname(__FILE__), '../init')) # load table_display
|
metadata
ADDED
@@ -0,0 +1,141 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: table_display
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
hash: 11
|
5
|
+
prerelease:
|
6
|
+
segments:
|
7
|
+
- 0
|
8
|
+
- 5
|
9
|
+
- 0
|
10
|
+
version: 0.5.0
|
11
|
+
platform: ruby
|
12
|
+
authors:
|
13
|
+
- Will Bryant
|
14
|
+
autorequire:
|
15
|
+
bindir: bin
|
16
|
+
cert_chain: []
|
17
|
+
|
18
|
+
date: 2012-08-18 00:00:00 Z
|
19
|
+
dependencies:
|
20
|
+
- !ruby/object:Gem::Dependency
|
21
|
+
name: rake
|
22
|
+
prerelease: false
|
23
|
+
requirement: &id001 !ruby/object:Gem::Requirement
|
24
|
+
none: false
|
25
|
+
requirements:
|
26
|
+
- - ">="
|
27
|
+
- !ruby/object:Gem::Version
|
28
|
+
hash: 3
|
29
|
+
segments:
|
30
|
+
- 0
|
31
|
+
version: "0"
|
32
|
+
type: :development
|
33
|
+
version_requirements: *id001
|
34
|
+
- !ruby/object:Gem::Dependency
|
35
|
+
name: sqlite3
|
36
|
+
prerelease: false
|
37
|
+
requirement: &id002 !ruby/object:Gem::Requirement
|
38
|
+
none: false
|
39
|
+
requirements:
|
40
|
+
- - ">="
|
41
|
+
- !ruby/object:Gem::Version
|
42
|
+
hash: 3
|
43
|
+
segments:
|
44
|
+
- 0
|
45
|
+
version: "0"
|
46
|
+
type: :development
|
47
|
+
version_requirements: *id002
|
48
|
+
- !ruby/object:Gem::Dependency
|
49
|
+
name: activerecord
|
50
|
+
prerelease: false
|
51
|
+
requirement: &id003 !ruby/object:Gem::Requirement
|
52
|
+
none: false
|
53
|
+
requirements:
|
54
|
+
- - ">="
|
55
|
+
- !ruby/object:Gem::Version
|
56
|
+
hash: 3
|
57
|
+
segments:
|
58
|
+
- 0
|
59
|
+
version: "0"
|
60
|
+
type: :development
|
61
|
+
version_requirements: *id003
|
62
|
+
description: |
|
63
|
+
Adds support for displaying your ActiveRecord tables, named scopes, collections, or
|
64
|
+
plain arrays in a table view when working in rails console, shell, or email template.
|
65
|
+
|
66
|
+
Enumerable#to_table returns the printable strings; Object#pt calls #to_table on its
|
67
|
+
first argument and puts out the result.
|
68
|
+
|
69
|
+
Columns you haven't loaded (eg. from using :select) are omitted, and derived/calculated
|
70
|
+
columns (eg. again, from using :select) are added.
|
71
|
+
|
72
|
+
Both #to_table and Object#pt methods take :only, :except, and :methods which work like
|
73
|
+
the #to_xml method to change what attributes/methods are output.
|
74
|
+
|
75
|
+
The normal output uses #inspect on the data values to make them printable, so you can
|
76
|
+
see what type the values had. When that's inconvenient or you'd prefer direct display,
|
77
|
+
you can pass the option :inspect => false to disable inspection.
|
78
|
+
|
79
|
+
email: will.bryant@gmail.com
|
80
|
+
executables: []
|
81
|
+
|
82
|
+
extensions: []
|
83
|
+
|
84
|
+
extra_rdoc_files: []
|
85
|
+
|
86
|
+
files:
|
87
|
+
- .gitignore
|
88
|
+
- Gemfile
|
89
|
+
- MIT-LICENSE
|
90
|
+
- README
|
91
|
+
- Rakefile
|
92
|
+
- init.rb
|
93
|
+
- lib/table_display.rb
|
94
|
+
- lib/table_display/version.rb
|
95
|
+
- table_display.gemspec
|
96
|
+
- test/database.yml
|
97
|
+
- test/fixtures/projects.yml
|
98
|
+
- test/fixtures/tasks.yml
|
99
|
+
- test/schema.rb
|
100
|
+
- test/table_display_test.rb
|
101
|
+
- test/test_helper.rb
|
102
|
+
homepage: http://github.com/willbryant/table_display
|
103
|
+
licenses: []
|
104
|
+
|
105
|
+
post_install_message:
|
106
|
+
rdoc_options: []
|
107
|
+
|
108
|
+
require_paths:
|
109
|
+
- lib
|
110
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
111
|
+
none: false
|
112
|
+
requirements:
|
113
|
+
- - ">="
|
114
|
+
- !ruby/object:Gem::Version
|
115
|
+
hash: 3
|
116
|
+
segments:
|
117
|
+
- 0
|
118
|
+
version: "0"
|
119
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
120
|
+
none: false
|
121
|
+
requirements:
|
122
|
+
- - ">="
|
123
|
+
- !ruby/object:Gem::Version
|
124
|
+
hash: 3
|
125
|
+
segments:
|
126
|
+
- 0
|
127
|
+
version: "0"
|
128
|
+
requirements: []
|
129
|
+
|
130
|
+
rubyforge_project:
|
131
|
+
rubygems_version: 1.8.15
|
132
|
+
signing_key:
|
133
|
+
specification_version: 3
|
134
|
+
summary: Adds support for displaying your ActiveRecord tables, named scopes, collections, or plain arrays in a table view when working in script/console, shell, or email template.
|
135
|
+
test_files:
|
136
|
+
- test/database.yml
|
137
|
+
- test/fixtures/projects.yml
|
138
|
+
- test/fixtures/tasks.yml
|
139
|
+
- test/schema.rb
|
140
|
+
- test/table_display_test.rb
|
141
|
+
- test/test_helper.rb
|