7

I have an array and my goal is to print the code in such a way that it puts out the following:

Output Table

How can I do that?

5
  • 2
    ... what does your array look like? what have tried so far? Commented Feb 23, 2015 at 22:21
  • So that each and every reader who prepares an answer doesn't have to construct the same object containing input data, please edit to provide it, so they can just copy and paste. For example, arr = [{date: "2014-12-01", from: "Ferdous", subject: "Homework this week"}, {date: "2014-12-01", from: "Dajana", subject: "Keep on coding! :)"}, {date: 2014-12-02, from: "Madonna", subject: "Re: Homework this week"}]. Commented Feb 23, 2015 at 22:26
  • 1
    you need to provide some more info on your environment (is it a rails project? is this an ActiveRecord table? etc) and some things about your code (eg a sample of the relevant class) and the attempts you 've made so far. Commented Feb 23, 2015 at 22:30
  • 1
    Might take a look at the hirb gem github.com/cldwalker/hirb Commented Feb 23, 2015 at 23:06
  • You really should accept the below answer. It is the right answer! Commented Dec 31, 2018 at 5:27

2 Answers 2

34

I imagine there are lots of gems available for doing this, but if you want to roll-your-own, you could do it like this, in a fairly general way:

Your input is comprised of column labels:

col_labels = { date: "Date", from: "From", subject: "Subject" }

and the data for the rows:

arr = [{date: "2014-12-01", from: "Ferdous", subject: "Homework this week"},
       {date: "2014-12-01", from: "Dajana", subject: "Keep on coding! :)"},
       {date: "2014-12-02", from: "Ariane", subject: "Re: Homework this week"}]

where col_labels and the elements of arr have the same keys.

From this point on, the code is general. First construct a hash @columns (which I've made an instance variable for convenience).

@columns = col_labels.each_with_object({}) { |(col,label),h|
  h[col] = { label: label,
             width: [arr.map { |g| g[col].size }.max, label.size].max } }
  # => {:date=>    {:label=>"Date",    :width=>10},
  #     :from=>    {:label=>"From",    :width=>7},
  #     :subject=> {:label=>"Subject", :width=>22}}

def write_header
  puts "| #{ @columns.map { |_,g| g[:label].ljust(g[:width]) }.join(' | ') } |"
end

def write_divider
  puts "+-#{ @columns.map { |_,g| "-"*g[:width] }.join("-+-") }-+"
end

def write_line(h)
  str = h.keys.map { |k| h[k].ljust(@columns[k][:width]) }.join(" | ")
  puts "| #{str} |"
end

write_divider
write_header
write_divider
arr.each { |h| write_line(h) }
write_divider

+------------+---------+------------------------+
| Date       | From    | Subject                |
+------------+---------+------------------------+
| 2014-12-01 | Ferdous | Homework this week     |
| 2014-12-01 | Dajana  | Keep on coding! :)     |
| 2014-12-02 | Ariane  | Re: Homework this week |
+------------+---------+------------------------+

If you want to reverse the display and make it a bit larger, like yours, first execute:

$_!.reverse
$_@ += 4

Output Table

Sign up to request clarification or add additional context in comments.

1 Comment

Giant answer.. You made Postgresql DB like output ... Congratulations...+1
2

The easiest way to do it is with the table_print gem: http://tableprintgem.com

For example, using the array from the other answer,

your_array = [
  {date: "2014-12-01", from: "Ferdous", subject: "Homework this week"},
  {date: "2014-12-01", from: "Dajana", subject: "Keep on coding! :)"},
  {date: "2014-12-02", from: "Ariane", subject: "Re: Homework this week"},
]
tp your_array

you would get the following result:

DATE       | FROM    | SUBJECT
-----------|---------|-----------------------
2014-12-01 | Ferdous | Homework this week
2014-12-01 | Dajana  | Keep on coding! :)
2014-12-02 | Ariane  | Re: Homework this week

You can also specify the columns you want to include (as strings or symbols):

tp your_array, "subject", :from

This is very useful when your array is from an ActiveRecord query, and displaying every single column would make the output unreadable:

tp User.all, :full_name, :e-mail_address

You can even access related models:

tp User.all, :full_name, "posts.title"

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.