table_print 0.2.3 → 1.0.0.rc3

Sign up to get free protection for your applications and to get access to all the features.
data/.rspec ADDED
@@ -0,0 +1 @@
1
+ --color
data/.rvmrc CHANGED
@@ -4,7 +4,7 @@
4
4
  # development environment upon cd'ing into the directory
5
5
 
6
6
  # First we specify our desired <ruby>[@<gemset>], the @gemset name is optional.
7
- environment_id="ruby-1.9.2-p290@table_print"
7
+ environment_id="ruby-1.8.7-p358"
8
8
 
9
9
  #
10
10
  # Uncomment the following lines if you want to verify rvm version per project
data/.travis.yml CHANGED
@@ -3,3 +3,8 @@ rvm:
3
3
  - 1.8.7
4
4
  - 1.9.2
5
5
  - 1.9.3
6
+ - jruby-18mode
7
+ - jruby-19mode
8
+ - rbx-18mode
9
+ - rbx-19mode
10
+ - ree
data/Gemfile CHANGED
@@ -1,13 +1,14 @@
1
- source "http://rubygems.org"
2
- # Add dependencies required to use your gem here.
3
- # Example:
4
- # gem "activesupport", ">= 2.3.5"
1
+ source :rubygems
2
+
3
+ gemspec :name => 'table_print'
4
+
5
+ gem 'bundler', "~> 1.1"
5
6
 
6
- # Add dependencies to develop your gem here.
7
- # Include everything needed to run rake, tests, features, etc.
8
7
  group :development do
9
- gem "shoulda", ">= 0"
10
- gem "bundler", "~> 1.0.0"
11
- gem "jeweler", "~> 1.5.2"
12
- gem "rcov", ">= 0"
8
+ gem 'relish'
13
9
  end
10
+
11
+ group :test do
12
+ gem 'cat', "~> 0.2.1"
13
+ end
14
+
data/README.rdoc CHANGED
@@ -1,5 +1,8 @@
1
1
  = table_print
2
2
 
3
+ {<img src="https://secure.travis-ci.org/arches/table_print.png" />}[http://travis-ci.org/arches/table_print]
4
+
5
+
3
6
  Turn objects into nicely formatted columns for easy reading
4
7
 
5
8
  TablePrint formats an object or array of objects into columns for easy reading. To do this,
@@ -19,15 +22,16 @@ it assumes the objects in your array all respond to the same methods.
19
22
  # Outside rails
20
23
  $ irb
21
24
  > require 'table_print'
22
- > tp array_of_objects, options = {}
25
+ > tp array_of_objects, options
23
26
 
24
27
  # Inside rails, the gem has already been required by your Gemfile so all you need to do is
25
28
  $ rails c
26
- > tp array_of_objects, options = {}
29
+ > tp array_of_objects, options
27
30
 
28
31
  You should see something like this:
29
32
 
30
- NAME | SUMMARY | TITLE
33
+ > tp Book.all
34
+ AUTHOR | SUMMARY | TITLE
31
35
  -----------------------------------------------------------------------
32
36
  Michael Connelly | Another book by Michael Con... | The Fifth Witness
33
37
  Manning Mardale | From acclaimed historian Ma... | Malcolm X
@@ -35,63 +39,112 @@ You should see something like this:
35
39
 
36
40
  TablePrint tries to use sensible defaults to choose the columns to show. If you're inspecting ActiveRecord objects, it
37
41
  uses the ActiveRecord column names. You can customize the output to show fewer columns, or show other methods you've written
38
- on your model.
42
+ on your model. Use symbols or strings to reference the columns.
39
43
 
40
- # Maybe you story a user's hourly rate but you want to see their yearly income
41
- > tp User.limit(30), {:include => :yearly_income, :except => :hourly_rate}
44
+ # Maybe you store a user's hourly rate but you want to see their yearly income
45
+ tp User.limit(30), :include => :yearly_income, :except => :hourly_rate
42
46
 
43
47
  # Maybe all you care about is their mailing info
44
- > tp User.limit(30), {:only => [:address, :city, :state, :zip]}
48
+ tp User.limit(30), :address, 'city', 'state', :zip
45
49
 
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
- option is useless at the moment. You are still able to use <b>:only</b> and <b>:except</b>.
50
+ If you're not using ActiveRecord, the TablePrint default is to show all the methods defined directly on your object (nothing
51
+ from superclasses/mixins).
48
52
 
49
53
  You can reference nested objects with the method chain required to reach them. Say you had some users who wrote books, and those
50
54
  books had photos.
51
55
 
52
- > tp array_of_objects, :only => ["name", "books.title", "books.photos.caption"]
53
-
54
- NAME | BOOKS > TITLE | BOOKS > PHOTOS > CAPTION
56
+ > tp Author.limit(3), "name", "books.title", "books.photos.caption"
57
+ NAME | BOOKS.TITLE | BOOKS.PHOTOS.CAPTION
55
58
  -------------------------------------------------------------------------
56
- Michael Connelly | |
57
- | The Fifth Witness |
58
- | | Susan was running, fast, away...
59
+ Michael Connelly | The Fifth Witness | Susan was running, fast, away...
59
60
  | | Along came a spider.
60
61
  | Malcolm X |
61
- | Bossypants |
62
- | | Yes! Yes! A thousand times ye...
62
+ | Bossypants | Yes! Yes! A thousand times ye...
63
63
  | | Don't see many like you aroun...
64
64
  Carrot Top | |
65
- Milton Greene | |
66
- | How I Learned |
67
- | | Once upon a time, I was a sma...
65
+ Milton Greene | How I Learned | Once upon a time, I was a sma...
68
66
  | | Lemons are yellow, limes are ...
69
67
  | | Never as a woman her age. I l...
70
- | Desperados |
71
- | | Avast.
68
+ | Desperados | Avast.
72
69
  | | Giraffes lived a peaceful exi...
73
70
 
74
71
 
75
72
  === Column options
76
73
 
77
74
  Pass options to individual columns through the options hash by using the display method as the hash key. Eg, if you wanted
78
- to rename the <b>pay_rate</b> column to <b>Special User Payment Teir</b>,
75
+ a skinny email column, set the width explicitly:
76
+
77
+ tp User.all, :email => {:width => 12}
78
+
79
+ Available column options:
80
+
81
+ * *display_method* - string/symbol/proc - used to populate the column. Can be a method name or a proc. See below.
82
+ * *formatters* - array of objects - each will be called in turn as the cells are printed. Must define a 'format' method. See below.
83
+ * *time_format* - string - passed to strftime[http://www.ruby-doc.org/core-1.9.3/Time.html#method-i-strftime], only affects time columns
84
+ * *width* - integer - how wide you want your column. Currently cannot exceed max_width.
85
+
86
+ ==== Display method
87
+
88
+ Columns are named after hash keys. To rename a column, use the name you want as the key, and pass the method as an option.
89
+
90
+ tp User.all, :active => {:display_method => :active_in_the_past_six_months} # the User class defines active_in_the_past_six_months method
91
+
92
+ ==== Lambdas
93
+
94
+ You can pass a proc as the display_method for a column:
79
95
 
80
- tp User.all, :pay_rate => {:name => "Special User Payment Teir"}
96
+ tp User.all, :email, :monthly_payment, :yearly_payment => lambda{|u| u.monthly_payment * 12}
81
97
 
82
- Columns have other options, including:
98
+ Or if you want to pass other options along with the lambda:
83
99
 
84
- <b>name</b>: Use this in the column header instead of the name of the display method.
100
+ tp User.all, :yearly_payment => {:display_method => lambda{|u| u.monthly_payment * 12}, :width => 10}
85
101
 
86
- <b>max_field_length:</b> <i>(default: 30)</i> Field lengths are determined based on the data in the column. Setting your own max
87
- will ensure that the column is as skinny as possible, but never above the number you provide.
102
+ ==== Column formatters
88
103
 
89
- <b>field_length:</b> Useful for very large data sets, this option will explicitly set the column width regardless of the data
90
- it contains. The max_field_length option takes precedence over field_length - ie, field_length can't be longer than max_field_length.
104
+ Similar to a lambda column, you can use a column formatter to reuse code across prints. Any object with a 'format' method
105
+ can be used to filter a column. This could also be used for coloring output.
91
106
 
107
+ class NoNewlineFormatter
108
+ def format(value)
109
+ value.to_s.gsub(/\r\n/, " ")
110
+ end
111
+ end
112
+
113
+ tp User.all, :bio => {:formatters => [NoNewlineFormatter.new]} # strip newlines from user bios
114
+
115
+
116
+ === Config
117
+
118
+ Use `tp.set` and `tp.clear` to set options on a class-by-class basis.
119
+
120
+ tp.set User, :id, :email # now whenever you print users, the only columns shown will be id and email
121
+
122
+ > tp User.first
123
+ ID | EMAIL
124
+ ----------------
125
+ 1 | foo@bar.com
126
+
127
+ # the config sets a 'baseline' for each print. You can still include/except columns:
128
+ > tp User.first, :except => :email
129
+ ID
130
+ --
131
+ 17
132
+
133
+ # you can still provide a specific set of columns:
134
+ > tp User.first, :first_name
135
+ FIRST_NAME
136
+ ----------
137
+ Phooey
138
+
139
+ tp.clear User # back to square one - print all the columns we can find
140
+
141
+ You can also set individual options:
142
+
143
+ tp.set :max_width, 10 # columns won't exceed 10 characters
144
+ tp.set :time_format, "%Y" # date columns will only show the year
92
145
 
93
146
  == Contributing to table_print
94
-
147
+
95
148
  * Check out the latest master to make sure the feature hasn't been implemented or the bug hasn't been fixed yet
96
149
  * Check out the issue tracker to make sure someone already hasn't requested it and/or contributed it
97
150
  * Fork the project
@@ -102,5 +155,5 @@ it contains. The max_field_length option takes precedence over field_length - ie
102
155
 
103
156
  == Copyright
104
157
 
105
- Copyright (c) 2011 Chris Doyle. See LICENSE.txt for further details.
158
+ Copyright (c) 2012 Chris Doyle. See LICENSE.txt for further details.
106
159
 
data/Rakefile CHANGED
@@ -22,25 +22,25 @@ Jeweler::Tasks.new do |gem|
22
22
  # Include your dependencies below. Runtime dependencies are required when using your gem,
23
23
  # and development dependencies are only needed for development (ie running rake tasks, tests, etc)
24
24
  # gem.add_runtime_dependency 'jabber4r', '> 0.1'
25
- # gem.add_development_dependency 'rspec', '> 1.2.3'
25
+ gem.add_development_dependency 'rspec'
26
+ gem.add_development_dependency 'cucumber'
26
27
  end
27
28
  Jeweler::RubygemsDotOrgTasks.new
28
29
 
29
- require 'rake/testtask'
30
- Rake::TestTask.new(:test) do |test|
31
- test.libs << 'lib' << 'test'
32
- test.test_files = Dir.glob("test/**/test_*.rb")
33
- test.verbose = true
34
- end
30
+ require 'rspec/core/rake_task'
31
+
32
+ desc 'Default: run specs and cucumber features.'
33
+ task :default => [:spec, :cucumber]
35
34
 
36
- require 'rcov/rcovtask'
37
- Rcov::RcovTask.new do |test|
38
- test.libs << 'test'
39
- test.pattern = 'test/**/test_*.rb'
40
- test.verbose = true
35
+ desc "Run specs"
36
+ RSpec::Core::RakeTask.new do |t|
41
37
  end
42
38
 
43
- task :default => :test
39
+ require "cucumber/rake/task"
40
+ desc 'Run cucumber features'
41
+ Cucumber::Rake::Task.new(:cucumber) do |task|
42
+ task.cucumber_opts = ["features"]
43
+ end
44
44
 
45
45
  begin
46
46
  require 'rdoc/task'
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.2.3
1
+ 1.0.0.rc3
@@ -0,0 +1,48 @@
1
+ Feature: Adding columns
2
+ Scenario: With the :include option
3
+ Given a class named Foo
4
+ Given Foo has attributes herp, blog
5
+
6
+ Given a class named Foo::Blog
7
+ Given Foo::Blog has attributes title, author
8
+ Given Foo::Blog has a class method named foo with lambda{"just testing!"}
9
+ Given Foo::Blog has a method named two_args with lambda{|a, b| "Called with #{a}, #{b}"}
10
+
11
+ When I instantiate a Foo with {:herp => "derp"}
12
+ When I instantiate a Foo::Blog with {:title => "post!", :author => 'Ryan'} and assign it to foo.blog
13
+ And table_print Foo, {:include => ["blog.author", "blog.title"]}
14
+ Then the output should contain
15
+ """
16
+ HERP | BLOG.AUTHOR | BLOG.TITLE
17
+ -------------------------------
18
+ derp | Ryan | post!
19
+ """
20
+
21
+ Scenario: Providing a named proc
22
+ Given a class named Blog
23
+
24
+ Given Blog has attributes title, author
25
+
26
+ When I instantiate a Blog with {:title => "post!", :author => 'Ryan'}
27
+ And table_print Blog, {:wombat => {:display_method => lambda{|blog| blog.author.gsub(/[aeiou]/, "").downcase}}}
28
+ Then the output should contain
29
+ """
30
+ WOMBAT
31
+ ------
32
+ ryn
33
+ """
34
+ Scenario: Providing a named proc without saying 'display_method', eg :foo => lambda{}
35
+ Given a class named Blog
36
+
37
+ Given Blog has attributes title, author
38
+
39
+ When I instantiate a Blog with {:title => "post!", :author => 'Ryan'}
40
+ And table_print Blog, {:wombat => lambda{|blog| blog.author.gsub(/[aeiou]/, "").downcase}}
41
+ Then the output should contain
42
+ """
43
+ WOMBAT
44
+ ------
45
+ ryn
46
+ """
47
+ Scenario: Using a proc as a filter (ie, overriding an existing column with a proc)
48
+
@@ -0,0 +1,57 @@
1
+ Feature: Configuring output
2
+ Scenario: Setting a (max? or specific?) width for all columns
3
+ Scenario: Setting a specific width for an individual column
4
+ Given a class named Blog
5
+
6
+ Given Blog has attributes title, author
7
+
8
+ When I instantiate a Blog with {:title => "post!", :author => 'Ryan'}
9
+ And table_print Blog, {:include => {:author => {:width => 10}}}
10
+ Then the output should contain
11
+ """
12
+ TITLE | AUTHOR
13
+ ------------------
14
+ post! | Ryan
15
+ """
16
+ Scenario: Specifying configuration on a per-object basis
17
+ Given a class named Blog
18
+
19
+ Given Blog has attributes title, author
20
+
21
+ When I instantiate a Blog with {:title => "post!", :author => 'Ryan'}
22
+ And configure Blog with :title
23
+ And table_print Blog
24
+ Then the output should contain
25
+ """
26
+ TITLE
27
+ -----
28
+ post!
29
+ """
30
+ Scenario: Specifying configuration on a per-object basis with an included column
31
+ Given a class named Blog
32
+
33
+ Given Blog has attributes title, author
34
+
35
+ When I instantiate a Blog with {:title => "post!", :author => 'Ryan'}
36
+ And configure Blog with {:include => {:foobar => lambda{|b| b.title}}}
37
+ And table_print Blog
38
+ Then the output should contain
39
+ """
40
+ TITLE | AUTHOR | FOOBAR
41
+ -----------------------
42
+ post! | Ryan | post!
43
+ """
44
+ Scenario: Applying a formatter
45
+ Scenario: Setting a column name
46
+ Given a class named Blog
47
+
48
+ Given Blog has attributes title, author
49
+
50
+ When I instantiate a Blog with {:title => "post!", :author => 'Ryan'}
51
+ And table_print Blog, {:wombat => {:display_method => :author}}
52
+ Then the output should contain
53
+ """
54
+ WOMBAT
55
+ ------
56
+ Ryan
57
+ """
@@ -0,0 +1,28 @@
1
+ Feature: Excluding columns
2
+ Scenario: With the :except option
3
+ Given a class named Blog
4
+
5
+ Given Blog has attributes title, author
6
+
7
+ When I instantiate a Blog with {:title => "post!", :author => 'Ryan'}
8
+ And table_print Blog, {:except => :title}
9
+ Then the output should contain
10
+ """
11
+ AUTHOR
12
+ ------
13
+ Ryan
14
+ """
15
+
16
+ Scenario: By specifying columns
17
+ Given a class named Blog
18
+
19
+ Given Blog has attributes title, author, url
20
+
21
+ When I instantiate a Blog with {:title => "post!", :author => 'Ryan', :url => "http://google.com"}
22
+ And table_print Blog, [:author, :url]
23
+ Then the output should contain
24
+ """
25
+ AUTHOR | URL
26
+ --------------------------
27
+ Ryan | http://google.com
28
+ """
@@ -0,0 +1,86 @@
1
+ Feature: Sensible defaults
2
+
3
+ By default, table_print shows all "getter" methods defined on your object itself. This includes anything except:
4
+
5
+ * Methods defined in an object's parent class
6
+ * Methods defined in an object's included modules
7
+ * Methods whose name ends with an equals sign (ie, setter methods)
8
+ * Methods with an arity > 0 (ie, methods that take arguments)
9
+
10
+ Scenario: A simple object
11
+ Given a class named Foo
12
+ Given Foo has attributes herp
13
+ Given Foo has a method named derp with lambda{"hurrrrr"}
14
+
15
+ Given a class named Foo::Blog
16
+ Given Foo::Blog has attributes title, author
17
+ Given Foo::Blog has a class method named foo with lambda{"just testing!"}
18
+ Given Foo::Blog has a method named two_args with lambda{|a, b| "Called with #{a}, #{b}"}
19
+
20
+ When I instantiate a Foo::Blog with {:title => "First post!", :author => 'Ryan'}
21
+ And table_print Foo::Blog
22
+ Then the output should contain
23
+ """
24
+ TITLE | AUTHOR
25
+ --------------------
26
+ First post! | Ryan
27
+ """
28
+
29
+ Scenario: An array of objects
30
+ Given a class named Post
31
+ Given Post has attributes title, author
32
+ Given Post has a class method named foo with lambda{"just testing!"}
33
+ Given Post has a method named two_args with lambda{|a, b| "Called with #{a}, #{b}"}
34
+
35
+ Given a class named Blog
36
+ Given Blog has attributes posts
37
+
38
+ When I instantiate a Blog with {:posts => []}
39
+ When I instantiate a Post with {:title => "First post!", :author => 'Ryan'} and add it to blog.posts
40
+ When I instantiate a Post with {:title => "Second post!", :author => 'Ryan'} and add it to blog.posts
41
+ When I instantiate a Post with {:title => "Third post!", :author => 'Ryan'} and add it to blog.posts
42
+ And table_print blog.posts
43
+ Then the output should contain
44
+ """
45
+ TITLE | AUTHOR
46
+ ---------------------
47
+ First post! | Ryan
48
+ Second post! | Ryan
49
+ Third post! | Ryan
50
+ """
51
+
52
+ Scenario: Nested objects
53
+ Given a class named Comment
54
+ Given Comment has attributes id, username, body
55
+
56
+ Given a class named Blog
57
+ Given Blog has attributes id, comments
58
+
59
+ Given I instantiate a Blog with {:id => 1, :comments => []}
60
+ And I instantiate a Comment with {:id => 1, :username => 'chris', :body => 'once upon a time'} and add it to blog.comments
61
+ And I instantiate a Comment with {:id => 2, :username => 'joe', :body => 'once upon a time'} and add it to blog.comments
62
+ When I table_print Blog, [:id, "comments.id", "comments.username"]
63
+ Then the output should contain
64
+ """
65
+ ID | COMMENTS.ID | COMMENTS.USERNAME
66
+ ------------------------------------
67
+ 1 | 1 | chris
68
+ | 2 | joe
69
+ """
70
+
71
+ Scenario: An object with column info (like an ActiveRecord object)
72
+ Given a class named ColumnInfo
73
+ Given ColumnInfo has attributes name
74
+
75
+ Given a class named Blog
76
+ Given Blog has attributes title, author
77
+ Given Blog has a class method named columns with lambda{[Sandbox::ColumnInfo.new(:name => :title)]}
78
+
79
+ When I instantiate a Blog with {:title => "First post!", :author => 'Ryan'}
80
+ And table_print Blog
81
+ Then the output should contain
82
+ """
83
+ TITLE
84
+ -----------
85
+ First post!
86
+ """