table_format 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 6305bf0c58e332244e99cf17d886b464e2a171d5b3725c27fd99a6245bb6f240
4
+ data.tar.gz: 3b17401ae6d8e231c29504e59f86ce22f869533489e13cf9b8a93689bea21661
5
+ SHA512:
6
+ metadata.gz: 4de5cfd39d6f9afe11e02ecb9957489b4c2720804656abb065dad688e2c8b7ee39e2fe1a70bbd1ea61dda0886841161703f6c1f84ff37017bd34da3a6e39e35b
7
+ data.tar.gz: 17cd1665ed3203b7d01e7ca4a8ca1c2179ce0bd685276b99d9f9f90652f5aa879baf05442f75efd334c2a8b836a8959cd5e20b065e4099af7b69358a60936046
data/.gitignore ADDED
@@ -0,0 +1,3 @@
1
+ /*.gem
2
+ /*.html
3
+ /Gemfile.lock
data/.travis.yml ADDED
@@ -0,0 +1,3 @@
1
+ language: ruby
2
+ rvm:
3
+ - 2.5
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in advanced_annotate_models.gemspec
4
+ gemspec
data/README.org ADDED
@@ -0,0 +1,196 @@
1
+ #+html: <a href="https://badge.fury.io/rb/table_format"><img src="https://badge.fury.io/rb/table_format.svg" alt="Gem Version" height="18"></a>
2
+ #+html: <a href="https://travis-ci.org/akicho8/table_format"><img src="https://travis-ci.org/akicho8/table_format.svg?branch=master" /></a>
3
+ #+html: <a href="https://codeclimate.com/github/akicho8/table_format/maintainability"><img src="https://api.codeclimate.com/v1/badges/3af6a246ec61ddafd45d/maintainability" /></a>
4
+
5
+ * TableFormat
6
+
7
+ TableFormat shows text table like emacs org-table for easy reading.
8
+
9
+ #+BEGIN_SRC ruby
10
+ tp Object.constants.grep(/RUBY_/).map { |e| [e, Object.const_get(e)] }.to_h
11
+
12
+ # >> |---------------------+------------------------------------------------------------|
13
+ # >> | RUBY_VERSION | 2.5.0 |
14
+ # >> | RUBY_RELEASE_DATE | 2017-12-25 |
15
+ # >> | RUBY_PLATFORM | x86_64-darwin16 |
16
+ # >> | RUBY_PATCHLEVEL | 0 |
17
+ # >> | RUBY_DESCRIPTION | ruby 2.5.0p0 (2017-12-25 revision 61468) [x86_64-darwin16] |
18
+ # >> | RUBY_ENGINE | ruby |
19
+ # >> | RUBY_REVISION | 61468 |
20
+ # >> | RUBY_ENGINE_VERSION | 2.5.0 |
21
+ # >> | RUBY_COPYRIGHT | ruby - Copyright (C) 1993-2017 Yukihiro Matsumoto |
22
+ # >> |---------------------+------------------------------------------------------------|
23
+ #+END_SRC
24
+
25
+ ** Installation
26
+
27
+ Install as a standalone gem
28
+
29
+ #+BEGIN_SRC shell-script
30
+ $ gem install table_format
31
+ #+END_SRC
32
+
33
+ Or install within application using Gemfile
34
+
35
+ #+BEGIN_SRC shell-script
36
+ $ bundle add table_format
37
+ $ bundle install
38
+ #+END_SRC
39
+
40
+ ** Examples
41
+
42
+ *** Array of hash
43
+
44
+ #+BEGIN_SRC ruby
45
+ tp [{id: 1, name: 'alice'}, {id: 2, name: 'bob'}]
46
+ # >> |----+-------|
47
+ # >> | id | name |
48
+ # >> |----+-------|
49
+ # >> | 1 | alice |
50
+ # >> | 2 | bob |
51
+ # >> |----+-------|
52
+ #+END_SRC
53
+
54
+ *** Hash
55
+
56
+ #+BEGIN_SRC ruby
57
+ tp({id: 1, name: 'alice'})
58
+ # >> |------+-------|
59
+ # >> | id | 1 |
60
+ # >> | name | alice |
61
+ # >> |------+-------|
62
+ #+END_SRC
63
+
64
+ *** Array
65
+
66
+ #+BEGIN_SRC ruby
67
+ tp [:alice, :bob]
68
+ # >> |-------|
69
+ # >> | alice |
70
+ # >> | bob |
71
+ # >> |-------|
72
+ #+END_SRC
73
+
74
+ *** ActiveRecord or Mongoid
75
+
76
+ #+BEGIN_SRC ruby
77
+ ['alice', 'bob'].each { |e| User.create!(name: e) }
78
+ #+END_SRC
79
+
80
+ #+BEGIN_SRC ruby
81
+ tp User
82
+ # >> |----+-------|
83
+ # >> | id | name |
84
+ # >> |----+-------|
85
+ # >> | 1 | alice |
86
+ # >> | 2 | bob |
87
+ # >> |----+-------|
88
+ #+END_SRC
89
+
90
+ #+BEGIN_SRC ruby
91
+ tp User.limit(1)
92
+ # >> |----+-------|
93
+ # >> | id | name |
94
+ # >> |----+-------|
95
+ # >> | 1 | alice |
96
+ # >> |----+-------|
97
+ #+END_SRC
98
+
99
+ #+BEGIN_SRC ruby
100
+ tp User.first
101
+ # >> |------+-------|
102
+ # >> | id | 1 |
103
+ # >> | name | alice |
104
+ # >> |------+-------|
105
+ #+END_SRC
106
+
107
+ **** ActiveRecord::Result
108
+
109
+ #+BEGIN_SRC ruby
110
+ tp ActiveRecord::Base.connection.select_all('SELECT * FROM users')
111
+ # >> |----+-------|
112
+ # >> | id | name |
113
+ # >> |----+-------|
114
+ # >> | 1 | alice |
115
+ # >> | 2 | bob |
116
+ # >> |----+-------|
117
+ #+END_SRC
118
+
119
+ ** How to table as string
120
+
121
+ Use to_t method.
122
+
123
+ #+BEGIN_SRC ruby
124
+ puts [{id: 1, name: 'alice'}, {id: 2, name: 'bob'}].to_t
125
+ # >> |----+-------|
126
+ # >> | id | name |
127
+ # >> |----+-------|
128
+ # >> | 1 | alice |
129
+ # >> | 2 | bob |
130
+ # >> |----+-------|
131
+ #+END_SRC
132
+
133
+ ** Options
134
+
135
+ Pass as the second argument to tp or the first argument to to_t.
136
+
137
+ #+BEGIN_SRC ruby
138
+ tp 1
139
+ # >> |---|
140
+ # >> | 1 |
141
+ # >> |---|
142
+
143
+ tp 1, intersection_both: '+'
144
+ # >> +---+
145
+ # >> | 1 |
146
+ # >> +---+
147
+ #+END_SRC
148
+
149
+ *** Markdown format example
150
+
151
+ =markdown: true= has the same meaning as =intersection: '|', cover: false=
152
+
153
+ #+BEGIN_SRC ruby
154
+ tp [{id: 1, name: 'alice'}, {id: 2, name: 'bob'}], markdown: true
155
+ # >> | id | name |
156
+ # >> |----|-------|
157
+ # >> | 1 | alice |
158
+ # >> | 2 | bob |
159
+ #+END_SRC
160
+
161
+ #+BEGIN_SRC ruby
162
+ tp [{id: 1, name: 'alice'}, {id: 2, name: 'bob'}], intersection: '|', cover: false
163
+ # >> | id | name |
164
+ # >> |----|-------|
165
+ # >> | 1 | alice |
166
+ # >> | 2 | bob |
167
+ #+END_SRC
168
+
169
+ ** Global Options
170
+
171
+ #+BEGIN_SRC ruby
172
+ tp TableFormat.default_options
173
+ # >> |-------------------+-------|
174
+ # >> | markdown | false |
175
+ # >> | header | |
176
+ # >> | cover | true |
177
+ # >> | vertical | | |
178
+ # >> | intersection | + |
179
+ # >> | intersection_both | | |
180
+ # >> | horizon | - |
181
+ # >> | padding | |
182
+ # >> | in_code | UTF-8 |
183
+ # >> |-------------------+-------|
184
+
185
+ tp 1
186
+ # >> |---|
187
+ # >> | 1 |
188
+ # >> |---|
189
+
190
+ TableFormat.default_options[:intersection_both] = '+'
191
+
192
+ tp 1
193
+ # >> +---+
194
+ # >> | 1 |
195
+ # >> +---+
196
+ #+END_SRC
data/Rakefile ADDED
@@ -0,0 +1,5 @@
1
+ require "bundler/gem_tasks"
2
+
3
+ require "rspec/core/rake_task"
4
+ RSpec::Core::RakeTask.new(:spec)
5
+ task :default => :spec
@@ -0,0 +1,54 @@
1
+ $LOAD_PATH << '../lib'
2
+ require 'table_format'
3
+
4
+ tp :ok
5
+ tp 'foo'
6
+ tp :foo
7
+ tp [:alice, :bob]
8
+ tp({id: 1, name: 'alice'})
9
+ tp [{id: 1, name: 'alice'}, {id: 2, name: 'bob'}]
10
+ puts [{id: 1, name: 'alice'}, {id: 2, name: 'bob'}].to_t
11
+ puts [{'a': ['a']}].to_t
12
+ puts [{'a': {'a': 1}}].to_t
13
+ # >> |----|
14
+ # >> | ok |
15
+ # >> |----|
16
+ # >> |----|
17
+ # >> | ok |
18
+ # >> |----|
19
+ # >> |-----|
20
+ # >> | foo |
21
+ # >> |-----|
22
+ # >> |-----|
23
+ # >> | foo |
24
+ # >> |-----|
25
+ # >> |-------|
26
+ # >> | alice |
27
+ # >> | bob |
28
+ # >> |-------|
29
+ # >> |------+-------|
30
+ # >> | id | 1 |
31
+ # >> | name | alice |
32
+ # >> |------+-------|
33
+ # >> |----+-------|
34
+ # >> | id | name |
35
+ # >> |----+-------|
36
+ # >> | 1 | alice |
37
+ # >> | 2 | bob |
38
+ # >> |----+-------|
39
+ # >> |----+-------|
40
+ # >> | id | name |
41
+ # >> |----+-------|
42
+ # >> | 1 | alice |
43
+ # >> | 2 | bob |
44
+ # >> |----+-------|
45
+ # >> |-------|
46
+ # >> | a |
47
+ # >> |-------|
48
+ # >> | ["a"] |
49
+ # >> |-------|
50
+ # >> |---------|
51
+ # >> | a |
52
+ # >> |---------|
53
+ # >> | {:a=>1} |
54
+ # >> |---------|
@@ -0,0 +1,92 @@
1
+ $LOAD_PATH << '../lib'
2
+ require 'active_record'
3
+ require 'table_format'
4
+
5
+ # tp ::ActiveRecord::Result.ancestors
6
+
7
+ ActiveRecord::Base.establish_connection(adapter: 'sqlite3', database: ':memory:')
8
+ ActiveRecord::Migration.verbose = false
9
+ ActiveRecord::Schema.define do
10
+ create_table :users do |t|
11
+ t.string :name
12
+ end
13
+ end
14
+
15
+ class User < ActiveRecord::Base
16
+ end
17
+
18
+ ['alice', 'bob', 'carol'].each { |e| User.create!(name: e) }
19
+
20
+ tp User.limit(2)
21
+
22
+ tp User
23
+ tp User.first
24
+
25
+ p User.limit(1).class.name # => "ActiveRecord::Relation"
26
+ tp User.limit(1)
27
+ puts table_format(User.limit(1))
28
+
29
+ tp ActiveRecord::Base.connection.select_all('SELECT * FROM users')
30
+ tp ActiveRecord::Base.connection.select_one('SELECT * FROM users')
31
+ tp ActiveRecord::Base.connection.select_value('SELECT 1 + 2')
32
+
33
+ puts User.first.to_t
34
+
35
+ puts table_format(User.first)
36
+
37
+ puts Struct.new(:a, :b).new(1, 2).to_h.to_t
38
+
39
+ # >> |----+-------|
40
+ # >> | id | name |
41
+ # >> |----+-------|
42
+ # >> | 1 | alice |
43
+ # >> | 2 | bob |
44
+ # >> |----+-------|
45
+ # >> |----+-------|
46
+ # >> | id | name |
47
+ # >> |----+-------|
48
+ # >> | 1 | alice |
49
+ # >> | 2 | bob |
50
+ # >> | 3 | carol |
51
+ # >> |----+-------|
52
+ # >> |------+-------|
53
+ # >> | id | 1 |
54
+ # >> | name | alice |
55
+ # >> |------+-------|
56
+ # >> "ActiveRecord::Relation"
57
+ # >> |----+-------|
58
+ # >> | id | name |
59
+ # >> |----+-------|
60
+ # >> | 1 | alice |
61
+ # >> |----+-------|
62
+ # >> |----+-------|
63
+ # >> | id | name |
64
+ # >> |----+-------|
65
+ # >> | 1 | alice |
66
+ # >> |----+-------|
67
+ # >> |----+-------|
68
+ # >> | id | name |
69
+ # >> |----+-------|
70
+ # >> | 1 | alice |
71
+ # >> | 2 | bob |
72
+ # >> | 3 | carol |
73
+ # >> |----+-------|
74
+ # >> |------+-------|
75
+ # >> | id | 1 |
76
+ # >> | name | alice |
77
+ # >> |------+-------|
78
+ # >> |---|
79
+ # >> | 3 |
80
+ # >> |---|
81
+ # >> |------+-------|
82
+ # >> | id | 1 |
83
+ # >> | name | alice |
84
+ # >> |------+-------|
85
+ # >> |------+-------|
86
+ # >> | id | 1 |
87
+ # >> | name | alice |
88
+ # >> |------+-------|
89
+ # >> |---+---|
90
+ # >> | a | 1 |
91
+ # >> | b | 2 |
92
+ # >> |---+---|
@@ -0,0 +1,34 @@
1
+ $LOAD_PATH << '../lib'
2
+ require 'table_format'
3
+
4
+ tp 1, intersection_both: '+'
5
+
6
+ tp TableFormat.default_options
7
+ TableFormat.default_options.update(intersection_both: '+')
8
+ tp TableFormat.default_options
9
+
10
+ # >> +---+
11
+ # >> | 1 |
12
+ # >> +---+
13
+ # >> |-------------------+-------|
14
+ # >> | markdown | false |
15
+ # >> | header | |
16
+ # >> | cover | true |
17
+ # >> | vertical | | |
18
+ # >> | intersection | + |
19
+ # >> | intersection_both | | |
20
+ # >> | horizon | - |
21
+ # >> | padding | |
22
+ # >> | in_code | UTF-8 |
23
+ # >> |-------------------+-------|
24
+ # >> +-------------------+-------+
25
+ # >> | markdown | false |
26
+ # >> | header | |
27
+ # >> | cover | true |
28
+ # >> | vertical | | |
29
+ # >> | intersection | + |
30
+ # >> | intersection_both | + |
31
+ # >> | horizon | - |
32
+ # >> | padding | |
33
+ # >> | in_code | UTF-8 |
34
+ # >> +-------------------+-------+
@@ -0,0 +1,35 @@
1
+ $LOAD_PATH << '../lib'
2
+ require 'active_record'
3
+ require 'mongoid'
4
+ require 'table_format'
5
+
6
+ Mongo::Logger.logger.level = Logger::INFO
7
+ Mongoid::Config.connect_to('test')
8
+ Mongoid::Clients.default.database.drop
9
+
10
+ class User
11
+ include Mongoid::Document
12
+ field :name, type: String
13
+ end
14
+
15
+ ['alice', 'bob', 'carol'].each { |e| User.create!(name: e) }
16
+
17
+ tp User
18
+ tp User.first
19
+ tp User.limit(1)
20
+ # >> |--------------------------+-------|
21
+ # >> | _id | name |
22
+ # >> |--------------------------+-------|
23
+ # >> | 59ed43e9f6453f17bc8e4fd3 | alice |
24
+ # >> | 59ed43e9f6453f17bc8e4fd4 | bob |
25
+ # >> | 59ed43e9f6453f17bc8e4fd5 | carol |
26
+ # >> |--------------------------+-------|
27
+ # >> |------+--------------------------|
28
+ # >> | _id | 59ed43e9f6453f17bc8e4fd3 |
29
+ # >> | name | alice |
30
+ # >> |------+--------------------------|
31
+ # >> |--------------------------+-------|
32
+ # >> | _id | name |
33
+ # >> |--------------------------+-------|
34
+ # >> | 59ed43e9f6453f17bc8e4fd3 | alice |
35
+ # >> |--------------------------+-------|
@@ -0,0 +1,51 @@
1
+ $LOAD_PATH << '../lib'
2
+ require 'table_format'
3
+
4
+ array = [
5
+ {id: 1, name: 'alice' },
6
+ {id: 2, name: 'bob' },
7
+ ]
8
+
9
+ # tp with options
10
+ tp array, intersection: '|', cover: false
11
+
12
+ # to_t with options
13
+ array.to_t(intersection: '|', cover: false) # => "| id | name |\n|----|-------|\n| 1 | alice |\n| 2 | bob |\n"
14
+
15
+ puts
16
+
17
+ # set global options
18
+ TableFormat.default_options.update(intersection: '|', cover: false)
19
+ tp array
20
+
21
+ ######################################## markdown option
22
+
23
+ # tp with options
24
+ tp array, markdown: true
25
+
26
+ # to_t with options
27
+ array.to_t(markdown: true) # => "| id | name |\n|----|-------|\n| 1 | alice |\n| 2 | bob |\n"
28
+
29
+ puts
30
+
31
+ # set global options
32
+ TableFormat.default_options.update(markdown: true)
33
+ tp array
34
+ # >> | id | name |
35
+ # >> |----|-------|
36
+ # >> | 1 | alice |
37
+ # >> | 2 | bob |
38
+ # >>
39
+ # >> | id | name |
40
+ # >> |----|-------|
41
+ # >> | 1 | alice |
42
+ # >> | 2 | bob |
43
+ # >> | id | name |
44
+ # >> |----|-------|
45
+ # >> | 1 | alice |
46
+ # >> | 2 | bob |
47
+ # >>
48
+ # >> | id | name |
49
+ # >> |----|-------|
50
+ # >> | 1 | alice |
51
+ # >> | 2 | bob |
@@ -0,0 +1,24 @@
1
+ require 'table_format/version'
2
+ require 'table_format/generator'
3
+ require 'table_format/core_ext'
4
+
5
+ if defined?(Rails)
6
+ require 'table_format/railtie'
7
+ else
8
+ if defined?(ActiveSupport)
9
+ ActiveSupport.on_load(:active_record) do
10
+ include TableFormat::ActiveRecord
11
+ ::ActiveRecord::Result.include TableFormat::ActiveRecordResult
12
+
13
+ ::ActiveRecord::Relation.class_eval do
14
+ def to_t(**options)
15
+ TableFormat.generate(to_a.collect(&:attributes), options)
16
+ end
17
+ end
18
+
19
+ end
20
+ end
21
+ if defined?(Mongoid::Document)
22
+ Mongoid::Document.include(TableFormat::ActiveRecord)
23
+ end
24
+ end
@@ -0,0 +1,68 @@
1
+ require 'active_support/core_ext/kernel/concern'
2
+
3
+ module TableFormat
4
+ concern :ActiveRecord do
5
+ class_methods do
6
+ def to_t(**options)
7
+ TableFormat.generate(all.collect(&:attributes), options)
8
+ end
9
+ end
10
+
11
+ def to_t(**options)
12
+ TableFormat.generate(attributes, options)
13
+ end
14
+ end
15
+
16
+ concern :ActiveRecordResult do
17
+ def to_t(**options)
18
+ TableFormat.generate(collect(&:to_h), options)
19
+ end
20
+ end
21
+ end
22
+
23
+ Object.class_eval do
24
+ def to_t(**options)
25
+ case
26
+ when respond_to?(:to_h)
27
+ to_h.to_t(options)
28
+ when respond_to?(:to_a)
29
+ to_a.to_t(options)
30
+ else
31
+ TableFormat.generate([{self.class.name => self}], {header: false}.merge(options))
32
+ end
33
+ end
34
+ end
35
+
36
+ Kernel.class_eval do
37
+ private
38
+
39
+ def tp(object, **options)
40
+ object.tap do
41
+ table_format(object).display
42
+ end
43
+ end
44
+
45
+ def table_format(object, **options)
46
+ object.to_t(options)
47
+ end
48
+ end
49
+
50
+ Array.class_eval do
51
+ def to_t(**options)
52
+ TableFormat.generate(self, options)
53
+ end
54
+ end
55
+
56
+ Hash.class_eval do
57
+ def to_t(**options)
58
+ TableFormat.generate(self, options)
59
+ end
60
+ end
61
+
62
+ [Symbol, String, Numeric].each do |klass|
63
+ klass.class_eval do
64
+ def to_t(**options)
65
+ TableFormat.generate([{self.class.name => self}], {header: false}.merge(options))
66
+ end
67
+ end
68
+ end
@@ -0,0 +1,240 @@
1
+ # frozen_string_literal: true
2
+ require 'active_support/core_ext/string' # for blank?
3
+ require 'active_support/core_ext/class/attribute' # for class_attribute
4
+ require 'kconv'
5
+
6
+ module TableFormat
7
+ mattr_accessor :default_options do
8
+ {
9
+ markdown: false,
10
+ header: nil,
11
+ cover: true,
12
+ vertical: '|',
13
+ intersection: '+',
14
+ intersection_both: '|',
15
+ horizon: '-',
16
+ padding: ' ',
17
+ in_code: Kconv::UTF8,
18
+ }
19
+ end
20
+
21
+ def self.generate(*args, &block)
22
+ Generator.new(*args, &block).generate
23
+ end
24
+
25
+ class Generator
26
+ def self.default_options
27
+ warn "[DEPRECATED] `TableFormat::Generator.default_options' is deprecated. Use `TableFormat.default_options' instead."
28
+ TableFormat.default_options
29
+ end
30
+
31
+ def initialize(rows, **options)
32
+ @options = TableFormat.default_options.merge(options)
33
+
34
+ if @options[:markdown]
35
+ @options[:intersection] = '|'
36
+ @options[:cover] = false
37
+ end
38
+
39
+ @rows = rows
40
+ @column_names = nil
41
+ end
42
+
43
+ def generate
44
+ if @rows.blank?
45
+ return ''
46
+ end
47
+
48
+ pre_processes.each do |e|
49
+ if e[:_case][@rows]
50
+ @rows = e[:process][@rows]
51
+ if @options[:header].nil?
52
+ @options[:header] = e[:header]
53
+ end
54
+ @options[:align] ||= e[:align]
55
+ end
56
+ end
57
+
58
+ table_rows_build
59
+
60
+ out = []
61
+ if @options[:cover]
62
+ out << separater
63
+ end
64
+ if @column_names
65
+ out << header
66
+ out << separater
67
+ end
68
+ out << body
69
+ if @options[:cover]
70
+ out << separater
71
+ end
72
+ out.flatten * "\n" + "\n"
73
+ end
74
+
75
+ private
76
+
77
+ def table_rows_build
78
+ if @options[:header]
79
+ @column_names = all_columns
80
+ end
81
+ @table_rows = @rows.collect { |e| e.values_at(*all_columns) }
82
+ end
83
+
84
+ def all_columns
85
+ @all_columns ||= @rows.inject([]) { |a, e| a | e.keys }
86
+ end
87
+
88
+ def column_widths
89
+ @column_widths ||= ([@column_names] + @table_rows).compact.transpose.collect do |vertical_values|
90
+ vertical_values.collect { |e| str_width(e) }.max
91
+ end
92
+ end
93
+
94
+ def separater
95
+ @separater ||= _separater
96
+ end
97
+
98
+ def _separater
99
+ s = column_widths.collect { |e|
100
+ @options[:horizon] * (padding.size + e + padding.size)
101
+ }
102
+ s = s.join(@options[:intersection])
103
+ [@options[:intersection_both], s, @options[:intersection_both]].join
104
+ end
105
+
106
+ def header
107
+ @header ||= line_str(@column_names)
108
+ end
109
+
110
+ def body
111
+ @table_rows.collect { |row| line_str(row) }
112
+ end
113
+
114
+ def line_str(row)
115
+ s = row.collect.with_index {|e, i|
116
+ padding + just(e, i) + padding
117
+ }
118
+ s = s.join(@options[:vertical])
119
+ [@options[:vertical], s, @options[:vertical]].join
120
+ end
121
+
122
+ def padding
123
+ @options[:padding]
124
+ end
125
+
126
+ def just(value, i)
127
+ align = (@options[:align] || {}).fetch(all_columns[i]) do
128
+ Float(value) && :right rescue :left
129
+ end
130
+ space = ' ' * (column_widths[i] - str_width(value))
131
+ lspace = ''
132
+ rspace = ''
133
+ if align == :right
134
+ lspace = space
135
+ else
136
+ rspace = space
137
+ end
138
+ # If value is `[]`,
139
+ # executing to_s, it becomes `[]`.
140
+ # not executing to_s, it becomes empty string
141
+ [lspace, value.to_s, rspace].join
142
+ end
143
+
144
+ def str_width(str)
145
+ str.to_s.kconv(Kconv::EUC, @options[:in_code]).bytesize
146
+ end
147
+
148
+ def pre_processes
149
+ [
150
+ # Hash
151
+ {
152
+ _case: -> e { e.kind_of?(Hash) },
153
+ header: false,
154
+ process: -> e {
155
+ e.collect do |k, v|
156
+ {'(key)' => k.to_s, '(value)' => v.to_s}
157
+ end
158
+ },
159
+ align: {'(key)' => :right, '(value)' => :left},
160
+ },
161
+
162
+ # Array of Hash
163
+ {
164
+ _case: -> e { e.kind_of?(Array) && e.all? { |v| v.kind_of?(Hash) } },
165
+ header: true,
166
+ process: -> e { e },
167
+ },
168
+
169
+ # Array excluding Hash
170
+ {
171
+ _case: -> e { e.kind_of?(Array) && e.none? { |v| v.kind_of?(Hash) } },
172
+ header: false,
173
+ process: -> e {
174
+ e.collect do |v|
175
+ {'(array_element)' => v}
176
+ end
177
+ },
178
+ },
179
+
180
+ # Array containing Hash and others
181
+ {
182
+ _case: -> e { e.kind_of?(Array) && e.any? { |v| !v.kind_of?(Hash) } },
183
+ header: true,
184
+ process: -> e {
185
+ e.collect do |v|
186
+ if v.kind_of? Hash
187
+ v
188
+ else
189
+ {'(array_element)' => v}
190
+ end
191
+ end
192
+ },
193
+ },
194
+ ]
195
+ end
196
+ end
197
+ end
198
+
199
+ if $0 == __FILE__
200
+ rows = [
201
+ {id: 1, name: 'alice', description: '0123456789'},
202
+ {id: 2, name: 'bob', description: 'あいうえお'},
203
+ {id: 3, name: 'carol'},
204
+ ]
205
+ print TableFormat.generate({a: []})
206
+ print TableFormat.generate([])
207
+ print TableFormat.generate(rows)
208
+ print TableFormat.generate({a: 1, b: 2}, header: false)
209
+ print TableFormat.generate([["a", "b"], ["c", "d"]])
210
+ print TableFormat.generate([["a", "b"], {"c" => "d"}])
211
+ print TableFormat.generate({id: 1, created_at: "2000-01-01"})
212
+ end
213
+ # >> |---+----|
214
+ # >> | a | [] |
215
+ # >> |---+----|
216
+ # >> |----+-------+-------------|
217
+ # >> | id | name | description |
218
+ # >> |----+-------+-------------|
219
+ # >> | 1 | alice | 0123456789 |
220
+ # >> | 2 | bob | あいうえお |
221
+ # >> | 3 | carol | |
222
+ # >> |----+-------+-------------|
223
+ # >> |---+---|
224
+ # >> | a | 1 |
225
+ # >> | b | 2 |
226
+ # >> |---+---|
227
+ # >> |------------|
228
+ # >> | ["a", "b"] |
229
+ # >> | ["c", "d"] |
230
+ # >> |------------|
231
+ # >> |-----------------+---|
232
+ # >> | (array_element) | c |
233
+ # >> |-----------------+---|
234
+ # >> | ["a", "b"] | |
235
+ # >> | | d |
236
+ # >> |-----------------+---|
237
+ # >> |------------+------------|
238
+ # >> | id | 1 |
239
+ # >> | created_at | 2000-01-01 |
240
+ # >> |------------+------------|
@@ -0,0 +1,20 @@
1
+ module TableFormat
2
+ class Railtie < Rails::Railtie
3
+ initializer 'table_format' do
4
+ ActiveSupport.on_load(:active_record) do
5
+ include TableFormat::ActiveRecord
6
+ ::ActiveRecord::Result.include TableFormat::ActiveRecordResult
7
+
8
+ ::ActiveRecord::Relation.class_eval do
9
+ def to_t(**options)
10
+ TableFormat.generate(to_a.collect(&:attributes), options)
11
+ end
12
+ end
13
+ end
14
+
15
+ if defined?(Mongoid::Document)
16
+ Mongoid::Document.include(TableFormat::ActiveRecord)
17
+ end
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,3 @@
1
+ module TableFormat
2
+ VERSION = '0.0.1'
3
+ end
@@ -0,0 +1,47 @@
1
+ require_relative 'spec_helper'
2
+ require 'active_record'
3
+
4
+ ActiveRecord::Base.send(:include, TableFormat::ActiveRecord)
5
+ ActiveRecord::Base.establish_connection(adapter: 'sqlite3', database: ':memory:')
6
+ ActiveRecord::Migration.verbose = false
7
+
8
+ ActiveRecord::Schema.define do
9
+ create_table :users do |t|
10
+ t.string :name
11
+ end
12
+ end
13
+
14
+ class User < ActiveRecord::Base
15
+ end
16
+
17
+ describe TableFormat::ActiveRecord do
18
+ before do
19
+ 2.times { |i| User.create!(name: i) }
20
+ end
21
+
22
+ it do
23
+ User.to_t.should == <<~EOT
24
+ |----+------|
25
+ | id | name |
26
+ |----+------|
27
+ | 1 | 0 |
28
+ | 2 | 1 |
29
+ |----+------|
30
+ EOT
31
+ User.first.to_t.should == <<~EOT
32
+ |------+---|
33
+ | id | 1 |
34
+ | name | 0 |
35
+ |------+---|
36
+ EOT
37
+
38
+ ActiveRecord::Base.connection.select_all('select * from users').to_t.should == <<~EOT
39
+ |----+------|
40
+ | id | name |
41
+ |----+------|
42
+ | 1 | 0 |
43
+ | 2 | 1 |
44
+ |----+------|
45
+ EOT
46
+ end
47
+ end
@@ -0,0 +1,20 @@
1
+ require_relative 'spec_helper'
2
+
3
+ describe TableFormat do
4
+ require 'tempfile'
5
+ require 'active_support/testing/stream'
6
+ include ActiveSupport::Testing::Stream
7
+
8
+ it do
9
+ capture(:stdout) { tp 1 }.should == <<~EOT
10
+ |---|
11
+ | 1 |
12
+ |---|
13
+ EOT
14
+ end
15
+
16
+ it 'result is like p method' do
17
+ v = Object.new
18
+ quietly { tp v }.should == v
19
+ end
20
+ end
@@ -0,0 +1,8 @@
1
+ $LOAD_PATH.unshift File.expand_path('../../lib', __FILE__)
2
+ require 'table_format'
3
+
4
+ RSpec.configure do |config|
5
+ config.expect_with :rspec do |c|
6
+ c.syntax = [:should, :expect]
7
+ end
8
+ end
@@ -0,0 +1,128 @@
1
+ require_relative 'spec_helper'
2
+
3
+ describe TableFormat do
4
+ before do
5
+ @rows = [
6
+ {id: 1, name: 'alice', description: '0123456789'},
7
+ {id: 2, name: 'bob', description: 'あいうえお'},
8
+ {id: 3, name: 'bob'},
9
+ ]
10
+ end
11
+
12
+ it 'empty array' do
13
+ TableFormat.generate([]).should == ''
14
+ end
15
+
16
+ it 'default' do
17
+ TableFormat.generate(@rows).should == <<~EOT
18
+ |----+-------+-------------|
19
+ | id | name | description |
20
+ |----+-------+-------------|
21
+ | 1 | alice | 0123456789 |
22
+ | 2 | bob | あいうえお |
23
+ | 3 | bob | |
24
+ |----+-------+-------------|
25
+ EOT
26
+ end
27
+
28
+ it 'header: false' do
29
+ TableFormat.generate(@rows, header: false).should == <<~EOT
30
+ |---+-------+------------|
31
+ | 1 | alice | 0123456789 |
32
+ | 2 | bob | あいうえお |
33
+ | 3 | bob | |
34
+ |---+-------+------------|
35
+ EOT
36
+ end
37
+
38
+ it 'padding disable' do
39
+ TableFormat.generate(@rows, padding: '').should == <<~EOT
40
+ |--+-----+-----------|
41
+ |id|name |description|
42
+ |--+-----+-----------|
43
+ | 1|alice| 0123456789|
44
+ | 2|bob |あいうえお |
45
+ | 3|bob | |
46
+ |--+-----+-----------|
47
+ EOT
48
+ end
49
+
50
+ it 'markdown format' do
51
+ TableFormat.generate(@rows, intersection: '|', cover: false).should == <<~EOT
52
+ | id | name | description |
53
+ |----|-------|-------------|
54
+ | 1 | alice | 0123456789 |
55
+ | 2 | bob | あいうえお |
56
+ | 3 | bob | |
57
+ EOT
58
+
59
+ TableFormat.generate(@rows, markdown: true).should == <<~EOT
60
+ | id | name | description |
61
+ |----|-------|-------------|
62
+ | 1 | alice | 0123456789 |
63
+ | 2 | bob | あいうえお |
64
+ | 3 | bob | |
65
+ EOT
66
+ end
67
+
68
+ describe 'various to_t' do
69
+ it 'hash array' do
70
+ [{a: 1}].to_t.should == <<~EOT
71
+ |---|
72
+ | a |
73
+ |---|
74
+ | 1 |
75
+ |---|
76
+ EOT
77
+ end
78
+
79
+ it 'Hash' do
80
+ {a: 1}.to_t.should == <<~EOT
81
+ |---+---|
82
+ | a | 1 |
83
+ |---+---|
84
+ EOT
85
+ end
86
+
87
+ it 'String Array' do
88
+ ['a', 'b'].to_t.should == <<~EOT
89
+ |---|
90
+ | a |
91
+ | b |
92
+ |---|
93
+ EOT
94
+ end
95
+
96
+ it 'Others' do
97
+ 1.to_t.should be_present
98
+ '1'.to_t.should be_present
99
+ Module.new.should be_present
100
+ {[:a] => []}.to_t.should == <<~EOT
101
+ |------+----|
102
+ | [:a] | [] |
103
+ |------+----|
104
+ EOT
105
+ end
106
+
107
+ it 'Array of hashes and width is correct even when value is array' do
108
+ TableFormat.generate([{'a' => ['a']}]).should == <<~EOT
109
+ |-------|
110
+ | a |
111
+ |-------|
112
+ | ["a"] |
113
+ |-------|
114
+ EOT
115
+ end
116
+
117
+ it 'Array containing Hash and others' do
118
+ TableFormat.generate([["a", "b"], {"c" => "d"}]).should == <<~EOT
119
+ |-----------------+---|
120
+ | (array_element) | c |
121
+ |-----------------+---|
122
+ | ["a", "b"] | |
123
+ | | d |
124
+ |-----------------+---|
125
+ EOT
126
+ end
127
+ end
128
+ end
@@ -0,0 +1,30 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'table_format/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = 'table_format'
8
+ spec.version = TableFormat::VERSION
9
+ spec.author = 'akicho8'
10
+ spec.email = 'akicho8@gmail.com'
11
+ spec.homepage = 'https://github.com/akicho8/table_format'
12
+ spec.summary = 'TableFormat shows text table like emacs org-table for easy reading.'
13
+ spec.description = 'TableFormat shows text table like emacs org-table for easy reading.'
14
+ spec.platform = Gem::Platform::RUBY
15
+
16
+ spec.files = `git ls-files`.split($/)
17
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
18
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
19
+ spec.require_paths = ['lib']
20
+ spec.rdoc_options = ['--line-numbers', '--inline-source', '--charset=UTF-8', '--diagram', '--image-format=jpg']
21
+
22
+ spec.add_dependency 'activesupport'
23
+
24
+ spec.add_development_dependency 'bundler', '~> 1.3'
25
+ spec.add_development_dependency 'rake'
26
+ spec.add_development_dependency 'rspec'
27
+
28
+ spec.add_development_dependency 'activerecord'
29
+ spec.add_development_dependency 'sqlite3'
30
+ end
metadata ADDED
@@ -0,0 +1,155 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: table_format
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - akicho8
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2018-06-28 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: activesupport
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: '0'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: '0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: bundler
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '1.3'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '1.3'
41
+ - !ruby/object:Gem::Dependency
42
+ name: rake
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ">="
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ">="
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: rspec
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - ">="
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - ">="
67
+ - !ruby/object:Gem::Version
68
+ version: '0'
69
+ - !ruby/object:Gem::Dependency
70
+ name: activerecord
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - ">="
74
+ - !ruby/object:Gem::Version
75
+ version: '0'
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - ">="
81
+ - !ruby/object:Gem::Version
82
+ version: '0'
83
+ - !ruby/object:Gem::Dependency
84
+ name: sqlite3
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - ">="
88
+ - !ruby/object:Gem::Version
89
+ version: '0'
90
+ type: :development
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - ">="
95
+ - !ruby/object:Gem::Version
96
+ version: '0'
97
+ description: TableFormat shows text table like emacs org-table for easy reading.
98
+ email: akicho8@gmail.com
99
+ executables: []
100
+ extensions: []
101
+ extra_rdoc_files: []
102
+ files:
103
+ - ".gitignore"
104
+ - ".travis.yml"
105
+ - Gemfile
106
+ - README.org
107
+ - Rakefile
108
+ - examples/0100_basic.rb
109
+ - examples/0110_active_record.rb
110
+ - examples/0120_default_options.rb
111
+ - examples/0130_mongoid.rb
112
+ - examples/0140_markdown_format.rb
113
+ - lib/table_format.rb
114
+ - lib/table_format/core_ext.rb
115
+ - lib/table_format/generator.rb
116
+ - lib/table_format/railtie.rb
117
+ - lib/table_format/version.rb
118
+ - spec/active_record_spec.rb
119
+ - spec/core_ext_spec.rb
120
+ - spec/spec_helper.rb
121
+ - spec/table_format_spec.rb
122
+ - table_format.gemspec
123
+ homepage: https://github.com/akicho8/table_format
124
+ licenses: []
125
+ metadata: {}
126
+ post_install_message:
127
+ rdoc_options:
128
+ - "--line-numbers"
129
+ - "--inline-source"
130
+ - "--charset=UTF-8"
131
+ - "--diagram"
132
+ - "--image-format=jpg"
133
+ require_paths:
134
+ - lib
135
+ required_ruby_version: !ruby/object:Gem::Requirement
136
+ requirements:
137
+ - - ">="
138
+ - !ruby/object:Gem::Version
139
+ version: '0'
140
+ required_rubygems_version: !ruby/object:Gem::Requirement
141
+ requirements:
142
+ - - ">="
143
+ - !ruby/object:Gem::Version
144
+ version: '0'
145
+ requirements: []
146
+ rubyforge_project:
147
+ rubygems_version: 2.7.6
148
+ signing_key:
149
+ specification_version: 4
150
+ summary: TableFormat shows text table like emacs org-table for easy reading.
151
+ test_files:
152
+ - spec/active_record_spec.rb
153
+ - spec/core_ext_spec.rb
154
+ - spec/spec_helper.rb
155
+ - spec/table_format_spec.rb