breathing 0.0.4 → 0.0.9

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