breathing 0.0.4 → 0.0.9

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 62878c327e1da216456749f0d3d3b154a4d8d11528226f90cc7dadf855d2e6f2
4
- data.tar.gz: 7a27d00aca80c0a3837d1bfc7778ee1d507c2deb7719127a53745a86f25aa439
3
+ metadata.gz: 78f7bd77e2aacd87fe91b8e42eeb8dd590fac1a067c90c092a8069fa9d2a391f
4
+ data.tar.gz: cb6802aa877aa675fe62170d7d3fde082b1262439c33409a5a38169c90a05c8e
5
5
  SHA512:
6
- metadata.gz: 86f14f92c0a6b4953307c6a733daf0c378726f0e3d9f97703c29ff3e34ead58568b4b3d0d62ddd2cd34da40b6d1056cc6a6e1b096030276d6313745844a25998
7
- data.tar.gz: 51cb295e2097b87d2ba21faf62495087a5cae5a7db695e7703e219cbde57f883b4f776d39ca68258299ba6f33347c1bca3ce1608580b27f5a2e251f978c3c86f
6
+ metadata.gz: 1610bf010d660a7f0c1f00ed61b3235e75497220ef2b21c0f9a5c200b2c670c8495cbf905b782c7202f0236549e086296141d6e3d1b5fd1c24684d3a3af69335
7
+ data.tar.gz: 22d2262edfd99554875fbbaec0edac113c5e970a41f32126f7ebf18cc7b141987f9c58b1da1c02f4c1257e8f07a07e4a9a269c8876f6957bcc10cbac3767b161
data/README.md CHANGED
@@ -6,7 +6,7 @@ Logging mechanism using database triggers to store the old and new row states in
6
6
  ## Install
7
7
 
8
8
  ```
9
- gem install 'breathing'
9
+ gem install breathing
10
10
  ```
11
11
 
12
12
  ## Usage
@@ -49,6 +49,30 @@ Cleanup command.
49
49
 
50
50
  - Output file `breathing.xlsx`
51
51
 
52
+ ### out
53
+
54
+ ```
55
+ % DATABASE_URL="mysql2://user:pass@host:port/database" breathing out --table users --id 1
56
+ ```
57
+
58
+ ```
59
+ +----------------+------------------------+--------+----+-----+------+----------------------------+----------------------------+
60
+ | users |
61
+ +----------------+------------------------+--------+----+-----+------+----------------------------+----------------------------+
62
+ | change_logs.id | change_logs.created_at | action | id | age | name | created_at | updated_at |
63
+ +----------------+------------------------+--------+----+-----+------+----------------------------+----------------------------+
64
+ | 1 | 2020-12-18 22:43:32 | INSERT | 10 | 20 | a | 2020-12-18 13:43:32.316923 | 2020-12-18 13:43:32.316923 |
65
+ | 2 | 2020-12-18 22:43:32 | UPDATE | 10 | 21 | a | 2020-12-18 13:43:32.316923 | 2020-12-18 13:43:32.319706 |
66
+ | 3 | 2020-12-18 22:43:32 | DELETE | 10 | 21 | a | 2020-12-18 13:43:32.316923 | 2020-12-18 13:43:32.319706 |
67
+ +----------------+------------------------+--------+----+-----+------+----------------------------+----------------------------+
68
+ ```
69
+
70
+ ### tail
71
+
72
+ ```
73
+ % DATABASE_URL="mysql2://user:pass@host:port/database" breathing tail --table users --id 1
74
+ ```
75
+
52
76
  ## Compatibility
53
77
 
54
78
  - Ruby 2.3.0+
@@ -2,7 +2,7 @@ $:.push File.expand_path('lib', __dir__)
2
2
 
3
3
  Gem::Specification.new do |s|
4
4
  s.name = 'breathing'
5
- s.version = '0.0.4'
5
+ s.version = '0.0.9'
6
6
  s.platform = Gem::Platform::RUBY
7
7
  s.authors = ['Akira Kusumoto']
8
8
  s.email = ['akirakusumo10@gmail.com']
@@ -20,10 +20,11 @@ Gem::Specification.new do |s|
20
20
  s.executables = s.files.grep(%r{^exe/}) { |f| File.basename(f) }
21
21
  s.add_runtime_dependency 'thor'
22
22
 
23
- s.add_dependency 'activerecord', ['>= 5.0.0']
23
+ s.add_dependency 'activerecord', ['>= 6.0.0']
24
24
  s.add_dependency 'hairtrigger'
25
25
  s.add_dependency 'mysql2'
26
26
  s.add_dependency 'pg'
27
+ s.add_dependency 'terminal-table'
27
28
  s.add_dependency 'rubyXL', ['>= 3.4.0']
28
29
  s.add_development_dependency 'pry-byebug'
29
30
  s.add_development_dependency 'rspec', '~> 3.9'
@@ -4,6 +4,7 @@ require 'breathing/installer'
4
4
  require 'breathing/trigger'
5
5
  require 'breathing/change_log'
6
6
  require 'breathing/excel'
7
+ require 'breathing/terminal_table'
7
8
 
8
9
  module Breathing
9
10
  VERSION = Gem.loaded_specs['breathing'].version.to_s
@@ -28,5 +29,24 @@ module Breathing
28
29
  ActiveRecord::Base.establish_connection
29
30
  Breathing::Excel.new.create
30
31
  end
32
+
33
+ def render_terminal_table(table_name:, id: 1)
34
+ ActiveRecord::Base.establish_connection
35
+ puts Breathing::TerminalTable.new(table_name).render(id: id)
36
+ end
37
+
38
+ def tail_f(table_name:, id: 1)
39
+ ActiveRecord::Base.establish_connection
40
+ table = Breathing::TerminalTable.new(table_name)
41
+
42
+ loop do
43
+ text = table.render(id: id)
44
+ if text.present?
45
+ puts text
46
+ id = table.last_id + 1
47
+ end
48
+ sleep 5
49
+ end
50
+ end
31
51
  end
32
52
  end
@@ -12,5 +12,39 @@ module Breathing
12
12
  names = before_data.keys.present? ? before_data.keys : after_data.keys
13
13
  names.reject { |name| name == 'id' }
14
14
  end
15
+
16
+ def data
17
+ action == 'DELETE' ? before_data : after_data
18
+ end
19
+
20
+ def data_attributes
21
+ data_column_names.each.with_object('change_logs.id' => id,
22
+ 'change_logs.created_at' => created_at.to_s(:db),
23
+ 'action' => action,
24
+ 'id' => transaction_id) do |name, hash|
25
+ hash[name] = data[name]
26
+ end
27
+ end
28
+
29
+ def diff
30
+ return nil if action != 'UPDATE'
31
+
32
+ changed_attribute_columns.each.with_object({}) do |column_name, diff_hash|
33
+ diff_hash[column_name] = {before_data[column_name] => after_data[column_name]}
34
+ end
35
+ end
36
+
37
+ def attributes_for_excel
38
+ {
39
+ 'change_logs.id' => id,
40
+ 'created_at' => created_at.to_s(:db),
41
+ 'table_name' => table_name,
42
+ 'action' => action,
43
+ 'id' => transaction_id,
44
+ 'diff' => diff.to_s,
45
+ 'before_data' => before_data.to_s,
46
+ 'after_data' => after_data.to_s,
47
+ }
48
+ end
15
49
  end
16
50
  end
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
  require 'thor'
2
3
  require 'breathing'
3
4
 
@@ -6,26 +7,51 @@ module Breathing
6
7
  default_command :export
7
8
 
8
9
  desc 'install', 'Create table change_logs and create triggers'
10
+
9
11
  def install
10
12
  Breathing.install
11
13
  end
12
14
 
13
15
  desc 'uninstall', 'Drop table change_logs and drop triggers'
16
+
14
17
  def uninstall
15
18
  Breathing.uninstall
16
19
  end
17
20
 
18
21
  desc 'clear', 'Delete all records in change_logs table'
22
+
19
23
  def clear
20
24
  Breathing.clear
21
25
  end
22
26
 
23
27
  desc 'export', 'output xlsx'
28
+
24
29
  def export
25
30
  Breathing.export
26
31
  end
27
32
 
33
+ desc 'out', 'output stdout'
34
+ method_option :type, aliases: '-t', default: 'terminal_table', type: :string
35
+ method_option :table, type: :string, required: true
36
+ method_option :id, default: 1, type: :numeric
37
+ def out
38
+ if options[:table] == 'terminal_table'
39
+ Breathing.render_terminal_table(table_name: options[:table], id: options[:id].to_i)
40
+ else
41
+ # TODO
42
+ # Breathing.export(table_name: options[:table], id: options[:id].to_i)
43
+ end
44
+ end
45
+
46
+ desc 'tail', 'tail terminal_table'
47
+ method_option :table, type: :string, required: true
48
+ method_option :id, default: 1, type: :numeric
49
+ def tail
50
+ Breathing.tail_f(table_name: options[:table], id: options[:id].to_i)
51
+ end
52
+
28
53
  desc 'version', 'Show Version'
54
+
29
55
  def version
30
56
  say "Version: #{Breathing::VERSION}"
31
57
  end
@@ -11,64 +11,82 @@ module Breathing
11
11
  def create(id: 1, file_name: 'breathing.xlsx')
12
12
  sheet = @workbook[0]
13
13
  table_names = Breathing::ChangeLog.where('id >= ?', id).group(:table_name).pluck(:table_name)
14
- table_names.each do |table_name|
14
+ table_names.sort.each do |table_name|
15
15
  if sheet.sheet_name == 'Sheet1'
16
16
  sheet.sheet_name = table_name
17
17
  else
18
18
  sheet = @workbook.add_worksheet(table_name)
19
19
  end
20
20
 
21
- rows = Breathing::ChangeLog.where(table_name: table_name).where('id >= ?', id).order(:id)
21
+ rows = Breathing::ChangeLog.where(table_name: table_name).where('id >= ?', id).order(:id).to_a
22
22
 
23
- if first_row = rows.first
24
- add_header_row(sheet, first_row)
25
- end
23
+ next if rows.size.zero?
24
+
25
+ add_header_row(sheet, rows.first)
26
26
  add_body_rows(sheet, rows)
27
27
  add_style(sheet)
28
28
  end
29
29
 
30
+ add_change_logs_sheet(id) if table_names.size.positive?
31
+
30
32
  @workbook.write(file_name)
31
33
  end
32
34
 
33
35
  private
34
36
 
35
37
  def add_header_row(sheet, row)
36
- sheet.add_cell(0, 0, 'change_logs.id').change_font_bold(true)
37
- sheet.add_cell(0, 1, 'action').change_font_bold(true)
38
- sheet.add_cell(0, 2, 'id').change_font_bold(true)
39
- row.data_column_names.each.with_index(3) do |column_name, i|
40
- sheet.add_cell(0, i, column_name).change_font_bold(true)
38
+ header_color = 'ddedf3' # blue
39
+ row.data_attributes.keys.each.with_index do |header_column, column_index|
40
+ cell = sheet.add_cell(0, column_index, header_column)
41
+ cell.change_fill(header_color)
41
42
  end
42
43
  end
43
44
 
44
45
  def add_body_rows(sheet, rows)
45
- rows.each.with_index(1) do |row, i|
46
- sheet.add_cell(i, 0, row.id)
47
- sheet.add_cell(i, 1, row.action)
48
- sheet.add_cell(i, 2, row.transaction_id)
49
- row.data_column_names.each.with_index(3) do |column_name, j|
50
- data = row.action == 'DELETE' ? row.before_data : row.after_data
51
- cell_object = sheet.add_cell(i, j, data[column_name])
46
+ rows.each.with_index(1) do |row, row_number|
47
+ row.data_attributes.each.with_index do |(column_name, value), column_index|
48
+ cell = sheet.add_cell(row_number, column_index, value)
52
49
  if row.action == 'UPDATE' && column_name != 'updated_at' && row.changed_attribute_columns.include?(column_name)
53
- cell_object.change_fill('ffff00') # color: yellow
50
+ cell.change_fill('ffff00') # color: yellow
54
51
  elsif row.action == 'DELETE'
55
- cell_object.change_fill('d9d9d9') # color: grey
52
+ cell.change_fill('d9d9d9') # color: grey
56
53
  end
57
54
  end
58
55
  end
59
56
  end
60
57
 
61
58
  def add_style(sheet)
62
- sheet.sheet_data.rows.each.with_index do |row, i|
63
- row.cells.each do |cell|
59
+ sheet.sheet_data.rows.each.with_index do |row, row_index|
60
+ row.cells.each.with_index do |cell, column_index|
64
61
  %i[top bottom left right].each do |direction|
65
62
  cell.change_border(direction, 'thin')
66
63
  end
64
+ cell.change_border(:bottom, 'double') if row_index.zero?
67
65
 
68
- cell.change_border(:bottom, 'medium') if i.zero?
66
+ cell_width = cell.value.to_s.size + 2
67
+ sheet.change_column_width(column_index, cell_width) if cell_width > sheet.get_column_width(column_index)
69
68
  end
70
69
  end
70
+
71
71
  sheet.change_row_horizontal_alignment(0, 'center')
72
72
  end
73
+
74
+ def add_change_logs_sheet(id)
75
+ sheet = @workbook.add_worksheet(Breathing::ChangeLog.table_name)
76
+
77
+ change_logs = Breathing::ChangeLog.where('id >= ?', id).order(:id)
78
+ change_logs.first.attributes_for_excel.keys.each.with_index do |header_column, column_index|
79
+ cell = sheet.add_cell(0, column_index, header_column)
80
+ cell.change_fill('ddedf3') # blue
81
+ end
82
+
83
+ change_logs.each.with_index(1) do |change_log, row_number|
84
+ change_log.attributes_for_excel.each.with_index do |(_column_name, value), column_index|
85
+ sheet.add_cell(row_number, column_index, value)
86
+ end
87
+ end
88
+
89
+ add_style(sheet)
90
+ end
73
91
  end
74
92
  end
@@ -8,9 +8,9 @@ module Breathing
8
8
 
9
9
  class Installer
10
10
  def install
11
- raise Breathing::UnsupportedError, "Version MySQL 5.6 is not supported." unless database_version_valid?
11
+ raise Breathing::UnsupportedError, "Version MySQL 5.6 is not supported." unless database_supported_version?
12
12
 
13
- create_log_table unless log_table_exists?
13
+ create_log_table
14
14
 
15
15
  models.each do |model|
16
16
  column_names = model.columns.map(&:name)
@@ -21,14 +21,13 @@ module Breathing
21
21
  end
22
22
 
23
23
  def uninstall
24
- drop_log_table if log_table_exists?
25
-
24
+ drop_log_table
26
25
  models.each { |model| Breathing::Trigger.new(model, log_table_name).drop }
27
26
  end
28
27
 
29
28
  private
30
29
 
31
- def database_version_valid?
30
+ def database_supported_version?
32
31
  connection = ActiveRecord::Base.connection
33
32
  connection.adapter_name == "PostgreSQL" || (connection.adapter_name == 'Mysql2' && connection.raw_connection.info[:version].to_f >= 5.7)
34
33
  end
@@ -39,26 +38,22 @@ module Breathing
39
38
 
40
39
  def create_log_table(table_name: log_table_name)
41
40
  ActiveRecord::Schema.define version: 0 do
42
- create_table table_name, force: false do |t|
43
- t.string :action, null: false
44
- t.string :table_name, null: false
45
- t.string :transaction_id, null: false
46
- t.json :before_data, null: false
47
- t.json :after_data, null: false
48
- t.datetime :created_at, null: false, index: true
41
+ create_table table_name, if_not_exists: true do |t|
42
+ t.datetime :created_at, null: false, index: true
43
+ t.string :table_name, null: false
44
+ t.string :action, null: false
45
+ t.string :transaction_id, null: false
46
+ t.json :before_data, null: false
47
+ t.json :after_data, null: false
48
+
49
49
  t.index %w[table_name transaction_id]
50
50
  end
51
51
  end
52
52
  end
53
53
 
54
54
  def drop_log_table
55
- sql = "DROP TABLE #{log_table_name}"
56
- puts sql
57
- ActiveRecord::Base.connection.execute(sql)
58
- end
59
-
60
- def log_table_exists?
61
- ActiveRecord::Base.connection.table_exists?(log_table_name)
55
+ puts "DROP TABLE #{log_table_name}"
56
+ ActiveRecord::Base.connection.drop_table(log_table_name, if_exists: true)
62
57
  end
63
58
 
64
59
  def models
@@ -0,0 +1,30 @@
1
+ require 'breathing'
2
+ require 'terminal-table'
3
+
4
+ module Breathing
5
+ class TerminalTable
6
+ attr_reader :last_id
7
+
8
+ def initialize(table_name)
9
+ @last_id = 1
10
+ @table_name = table_name
11
+ end
12
+
13
+ def render(id: 1)
14
+ rows = Breathing::ChangeLog.where(table_name: @table_name).where("id >= ? ", id).order(:id)
15
+
16
+ return if rows.size.zero?
17
+
18
+ @table = Terminal::Table.new(title: rows.first.table_name,
19
+ headings: rows.first.data_attributes.keys,
20
+ rows: rows.map { |row| row.data_attributes.values })
21
+
22
+ @last_id = rows.last.id
23
+ @table.to_s
24
+ end
25
+
26
+ def rows
27
+ @table.rows
28
+ end
29
+ end
30
+ end
@@ -11,59 +11,25 @@ module Breathing
11
11
  end
12
12
 
13
13
  def create
14
- trigger_name = "#{log_table_name}_insert_#{model.table_name}"
15
-
16
- unless exists?(trigger_name)
17
- puts "CREATE TRIGGER #{trigger_name}"
14
+ exists_trigger_names = ActiveRecord::Base.connection.triggers.keys
18
15
 
19
- ActiveRecord::Base.connection.create_trigger(trigger_name).on(model.table_name).after(:insert) do
20
- <<-SQL
21
- INSERT INTO #{log_table_name} (action, table_name, transaction_id, before_data, after_data, created_at)
22
- VALUES ('INSERT', '#{model.table_name}', NEW.id,
23
- '{}',
24
- #{row_to_json(model.columns, 'NEW')},
25
- CURRENT_TIMESTAMP);
26
- SQL
27
- end
28
- end
16
+ trigger_name = "#{log_table_name}_insert_#{model.table_name}"
17
+ create_insert_trigger(trigger_name, model) if exists_trigger_names.exclude?(trigger_name)
29
18
 
30
19
  trigger_name = "#{log_table_name}_update_#{model.table_name}"
31
- unless exists?(trigger_name)
32
- puts "CREATE TRIGGER #{trigger_name}"
33
-
34
- ActiveRecord::Base.connection.create_trigger(trigger_name).on(model.table_name).before(:update).of(:updated_at) do
35
- <<-SQL
36
- INSERT INTO #{log_table_name} (action, table_name, transaction_id, before_data, after_data, created_at)
37
- VALUES ('UPDATE', '#{model.table_name}', NEW.id,
38
- #{row_to_json(model.columns, 'OLD')},
39
- #{row_to_json(model.columns, 'NEW')},
40
- CURRENT_TIMESTAMP);
41
- SQL
42
- end
43
- end
20
+ create_update_trigger(trigger_name, model) if exists_trigger_names.exclude?(trigger_name)
44
21
 
45
22
  trigger_name = "#{log_table_name}_delete_#{model.table_name}"
46
- unless exists?(trigger_name)
47
- puts "CREATE TRIGGER #{trigger_name}"
48
- ActiveRecord::Base.connection.create_trigger(trigger_name).on(model.table_name).after(:delete) do
49
- <<-SQL
50
- INSERT INTO #{log_table_name} (action, table_name, transaction_id, before_data, after_data, created_at)
51
- VALUES ('DELETE', '#{model.table_name}', OLD.id,
52
- #{row_to_json(model.columns, 'OLD')},
53
- '{}',
54
- CURRENT_TIMESTAMP);
55
- SQL
56
- end
57
- end
23
+ create_delete_trigger(trigger_name, model) if exists_trigger_names.exclude?(trigger_name)
58
24
  end
59
25
 
60
26
  def drop
61
- %w[insert update delete].each do |action|
62
- trigger_name = "#{log_table_name}_#{action}_#{model.table_name}"
27
+ trigger_names = %w[insert update delete].map { |action| "#{log_table_name}_#{action}_#{model.table_name}" }
63
28
 
29
+ trigger_names.each do |trigger_name|
64
30
  begin
65
31
  sql = "DROP TRIGGER IF EXISTS #{trigger_name}"
66
- if ActiveRecord::Base.connection.adapter_name == "PostgreSQL"
32
+ if postgresql?
67
33
  sql << " ON #{model.table_name} CASCADE;"
68
34
  sql << " DROP FUNCTION IF EXISTS #{trigger_name} CASCADE;"
69
35
  end
@@ -77,12 +43,50 @@ module Breathing
77
43
 
78
44
  private
79
45
 
80
- def exists?(trigger_name)
81
- ActiveRecord::Base.connection.triggers.keys.include?(trigger_name)
46
+ def postgresql?
47
+ ActiveRecord::Base.connection.adapter_name == 'PostgreSQL'
48
+ end
49
+
50
+ def create_trigger(name)
51
+ puts "CREATE TRIGGER #{name}"
52
+ ActiveRecord::Base.connection.create_trigger(name) # hairtrigger gem
53
+ end
54
+
55
+ def create_insert_trigger(trigger_name, model)
56
+ create_trigger(trigger_name).on(model.table_name).after(:insert) do
57
+ <<-SQL
58
+ INSERT INTO #{log_table_name} (created_at, action, table_name, transaction_id, before_data, after_data)
59
+ VALUES (CURRENT_TIMESTAMP, 'INSERT', '#{model.table_name}', NEW.id,
60
+ '{}',
61
+ #{row_to_json(model.columns, 'NEW')});
62
+ SQL
63
+ end
64
+ end
65
+
66
+ def create_update_trigger(trigger_name, model)
67
+ create_trigger(trigger_name).on(model.table_name).before(:update).of(:updated_at) do
68
+ <<-SQL
69
+ INSERT INTO #{log_table_name} (created_at, action, table_name, transaction_id, before_data, after_data)
70
+ VALUES (CURRENT_TIMESTAMP, 'UPDATE', '#{model.table_name}', NEW.id,
71
+ #{row_to_json(model.columns, 'OLD')},
72
+ #{row_to_json(model.columns, 'NEW')});
73
+ SQL
74
+ end
75
+ end
76
+
77
+ def create_delete_trigger(trigger_name, model)
78
+ create_trigger(trigger_name).on(model.table_name).after(:delete) do
79
+ <<-SQL
80
+ INSERT INTO #{log_table_name} (created_at, action, table_name, transaction_id, before_data, after_data)
81
+ VALUES (CURRENT_TIMESTAMP, 'DELETE', '#{model.table_name}', OLD.id,
82
+ #{row_to_json(model.columns, 'OLD')},
83
+ '{}');
84
+ SQL
85
+ end
82
86
  end
83
87
 
84
88
  def row_to_json(columns, state)
85
- if ActiveRecord::Base.connection.adapter_name == "PostgreSQL"
89
+ if postgresql?
86
90
  "row_to_json(#{state}.*)"
87
91
  else
88
92
  json_object_values = columns.each.with_object([]) do |column, array|
@@ -23,13 +23,18 @@ describe Breathing::Excel do
23
23
  end
24
24
 
25
25
  it 'multi sheets' do
26
- User.create!(name: 'a', age: 20)
26
+ user = User.create!(name: 'a', age: 20)
27
+ user.update!(age: 21)
28
+ user.destroy!
27
29
  Department.create!(name: 'a')
28
30
 
29
31
  Tempfile.open(['tmp', '.xlsx']) do |file|
30
32
  Breathing::Excel.new.create(file_name: file.path)
31
33
  workbook = RubyXL::Parser.parse(file.path)
32
- expect(workbook.sheets.size).to eq(2)
34
+ expect(workbook.sheets.map(&:name)).to eq(%w[departments users change_logs])
35
+ change_logs_sheet = workbook.worksheets.last
36
+
37
+ expect(change_logs_sheet.sheet_data.size).to eq(Breathing::ChangeLog.count + 1)
33
38
  end
34
39
  end
35
40
  end
@@ -0,0 +1,22 @@
1
+ require 'spec_helper'
2
+
3
+ describe Breathing::TerminalTable do
4
+ describe '#render' do
5
+ before { Breathing::Installer.new.install }
6
+ after do
7
+ Breathing::Installer.new.uninstall if ActiveRecord::Base.connection.adapter_name == "Mysql2"
8
+ end
9
+
10
+ it do
11
+ user = User.create!(name: 'a', age: 20)
12
+ user.update!(age: 21)
13
+ user.destroy!
14
+ expect(Breathing::ChangeLog.count).to eq(3)
15
+
16
+ table = Breathing::TerminalTable.new(:users)
17
+ puts table.render(id: 1)
18
+
19
+ expect(table.rows.size).to eq(3)
20
+ end
21
+ end
22
+ end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: breathing
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.4
4
+ version: 0.0.9
5
5
  platform: ruby
6
6
  authors:
7
7
  - Akira Kusumoto
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2020-12-14 00:00:00.000000000 Z
11
+ date: 2020-12-23 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: thor
@@ -30,14 +30,14 @@ dependencies:
30
30
  requirements:
31
31
  - - ">="
32
32
  - !ruby/object:Gem::Version
33
- version: 5.0.0
33
+ version: 6.0.0
34
34
  type: :runtime
35
35
  prerelease: false
36
36
  version_requirements: !ruby/object:Gem::Requirement
37
37
  requirements:
38
38
  - - ">="
39
39
  - !ruby/object:Gem::Version
40
- version: 5.0.0
40
+ version: 6.0.0
41
41
  - !ruby/object:Gem::Dependency
42
42
  name: hairtrigger
43
43
  requirement: !ruby/object:Gem::Requirement
@@ -80,6 +80,20 @@ dependencies:
80
80
  - - ">="
81
81
  - !ruby/object:Gem::Version
82
82
  version: '0'
83
+ - !ruby/object:Gem::Dependency
84
+ name: terminal-table
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - ">="
88
+ - !ruby/object:Gem::Version
89
+ version: '0'
90
+ type: :runtime
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - ">="
95
+ - !ruby/object:Gem::Version
96
+ version: '0'
83
97
  - !ruby/object:Gem::Dependency
84
98
  name: rubyXL
85
99
  requirement: !ruby/object:Gem::Requirement
@@ -143,9 +157,11 @@ files:
143
157
  - lib/breathing/cli.rb
144
158
  - lib/breathing/excel.rb
145
159
  - lib/breathing/installer.rb
160
+ - lib/breathing/terminal_table.rb
146
161
  - lib/breathing/trigger.rb
147
162
  - spec/app.rb
148
163
  - spec/breathing/excel_spec.rb
164
+ - spec/breathing/terminal_table_spec.rb
149
165
  - spec/breathing_spec.rb
150
166
  - spec/database.yml
151
167
  - spec/spec_helper.rb
@@ -175,6 +191,7 @@ summary: Audit logging for database
175
191
  test_files:
176
192
  - spec/app.rb
177
193
  - spec/breathing/excel_spec.rb
194
+ - spec/breathing/terminal_table_spec.rb
178
195
  - spec/breathing_spec.rb
179
196
  - spec/database.yml
180
197
  - spec/spec_helper.rb