table_display 0.5.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/.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
|