table_format 0.0.1

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.
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