lite-report 1.0.0

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.
@@ -0,0 +1,8 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'bundler/gem_tasks'
4
+ require 'rspec/core/rake_task'
5
+
6
+ RSpec::Core::RakeTask.new(:spec)
7
+
8
+ task default: :spec
@@ -0,0 +1 @@
1
+ theme: jekyll-theme-leap-day
@@ -0,0 +1,15 @@
1
+ #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
3
+
4
+ require 'bundler/setup'
5
+ require 'lite/report'
6
+
7
+ # You can add fixtures and/or initialization code here to make experimenting
8
+ # with your gem easier. You can also use a different console, if you like.
9
+
10
+ # (If you use this, don't forget to add pry to your Gemfile!)
11
+ # require "pry"
12
+ # Pry.start
13
+
14
+ require 'irb'
15
+ IRB.start(__FILE__)
@@ -0,0 +1,8 @@
1
+ #!/usr/bin/env bash
2
+ set -euo pipefail
3
+ IFS=$'\n\t'
4
+ set -vx
5
+
6
+ bundle install
7
+
8
+ # Do any other automated setup that you need to do here
@@ -0,0 +1,17 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'rails/generators'
4
+
5
+ module Lite
6
+ module Report
7
+ class InstallGenerator < Rails::Generators::Base
8
+
9
+ source_root File.expand_path('../templates', __FILE__)
10
+
11
+ def copy_initializer_file
12
+ copy_file('install.rb', 'config/initializers/lite-report.rb')
13
+ end
14
+
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,7 @@
1
+ # frozen_string_literal: true
2
+
3
+ Lite::Report.configure do |config|
4
+ config.csv_options = {}
5
+ config.data_options = {}
6
+ config.import_options = {}
7
+ end
@@ -0,0 +1,14 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'csv'
4
+ require 'lite/report/version'
5
+
6
+ %w[converters encoders filters headers processors records transporters].each do |file_name|
7
+ require "lite/report/helpers/#{file_name}"
8
+ end
9
+
10
+ %w[configuration base array hash record].each do |file_name|
11
+ require "lite/report/#{file_name}"
12
+ end
13
+
14
+ require 'generators/lite/report/install_generator'
@@ -0,0 +1,17 @@
1
+ # frozen_string_literal: true
2
+
3
+ class Lite::Report::Array < Lite::Report::Base
4
+
5
+ def export
6
+ generate_or_stream_export!
7
+ end
8
+
9
+ def import
10
+ CSV.foreach(@data, @csv_options)
11
+ .with_object([]) do |row, array|
12
+ row = convert_to_array!(row)
13
+ array << process_import_row!(row)
14
+ end
15
+ end
16
+
17
+ end
@@ -0,0 +1,56 @@
1
+ # frozen_string_literal: true
2
+
3
+ class Lite::Report::Base
4
+
5
+ include Lite::Report::Helpers::Converters
6
+ include Lite::Report::Helpers::Encoders
7
+ include Lite::Report::Helpers::Filters
8
+ include Lite::Report::Helpers::Headers
9
+ include Lite::Report::Helpers::Processors
10
+ include Lite::Report::Helpers::Records
11
+ include Lite::Report::Helpers::Transporters
12
+
13
+ def initialize(data, csv_options: {}, data_options: {}, import_options: {})
14
+ @data = data
15
+ @csv_options = Lite::Report.configuration.csv_options.merge(csv_options)
16
+ @data_options = Lite::Report.configuration.data_options.merge(data_options)
17
+ @import_options = Lite::Report.configuration.import_options.merge(import_options)
18
+ end
19
+
20
+ class << self
21
+
22
+ def export(data, csv_options: {}, data_options: {}, import_options: {})
23
+ klass = new(
24
+ data,
25
+ csv_options: csv_options,
26
+ data_options: data_options,
27
+ import_options: import_options
28
+ )
29
+
30
+ klass.export
31
+ end
32
+
33
+ def import(data, csv_options: {}, data_options: {}, import_options: {})
34
+ klass = new(
35
+ data,
36
+ csv_options: csv_options,
37
+ data_options: data_options,
38
+ import_options: import_options
39
+ )
40
+
41
+ klass.import
42
+ end
43
+
44
+ end
45
+
46
+ private
47
+
48
+ def values!(row)
49
+ case row.class.name
50
+ when 'CSV::Row' then row.fields
51
+ when 'Hash' then row.values
52
+ else row
53
+ end
54
+ end
55
+
56
+ end
@@ -0,0 +1,31 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Lite
4
+ module Report
5
+
6
+ class Configuration
7
+
8
+ attr_accessor :csv_options, :data_options, :import_options
9
+
10
+ def initialize
11
+ @csv_options = {}
12
+ @data_options = {}
13
+ @import_adapter = {}
14
+ end
15
+
16
+ end
17
+
18
+ def self.configuration
19
+ @configuration ||= Configuration.new
20
+ end
21
+
22
+ def self.configuration=(config)
23
+ @configuration = config
24
+ end
25
+
26
+ def self.configure
27
+ yield(configuration)
28
+ end
29
+
30
+ end
31
+ end
@@ -0,0 +1,28 @@
1
+ # frozen_string_literal: true
2
+
3
+ class Lite::Report::Hash < Lite::Report::Base
4
+
5
+ def export
6
+ assign_headers_to_csv_options!
7
+ generate_or_stream_export!
8
+ end
9
+
10
+ def import
11
+ CSV.foreach(@data, @csv_options)
12
+ .with_object([]) do |row, array|
13
+ next if header_row?(row)
14
+
15
+ row = convert_to_hash!(row)
16
+ array << process_import_row!(row)
17
+ end
18
+ end
19
+
20
+ private
21
+
22
+ def assign_headers_to_csv_options!
23
+ return unless write_headers?
24
+
25
+ @csv_options[:headers] ||= @data.first.keys
26
+ end
27
+
28
+ end
@@ -0,0 +1,28 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Lite
4
+ module Report
5
+ module Helpers
6
+ module Converters
7
+
8
+ private
9
+
10
+ def convert_to_array!(row)
11
+ case row.class.name
12
+ when 'CSV::Row' then row.fields
13
+ else row
14
+ end
15
+ end
16
+
17
+ def convert_to_hash!(row)
18
+ case row.class.name
19
+ when 'Array' then ::Hash[(0..(row.size - 1)).zip(row)]
20
+ when 'CSV::Row' then row.to_hash
21
+ else row
22
+ end
23
+ end
24
+
25
+ end
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,42 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Lite
4
+ module Report
5
+ module Helpers
6
+ module Encoders
7
+
8
+ private
9
+
10
+ def encode(cell)
11
+ return cell unless cell.is_a?(String)
12
+
13
+ cell.tr('"', '').encode!(*@data_options[:encode])
14
+ end
15
+
16
+ def encode?(delete: false)
17
+ return @data_options.delete(:encode) if delete
18
+
19
+ @data_options[:encode]
20
+ end
21
+
22
+ def encode!(row)
23
+ case row.class.name
24
+ when 'Hash' then encode_hash!(row)
25
+ else encode_array!(row)
26
+ end
27
+ end
28
+
29
+ def encode_array!(row)
30
+ row.map { |cell| encode(cell) }
31
+ end
32
+
33
+ def encode_hash!(row)
34
+ row.map.with_object({}) do |(key, val), hash|
35
+ hash[encode(key)] = encode(val)
36
+ end
37
+ end
38
+
39
+ end
40
+ end
41
+ end
42
+ end
@@ -0,0 +1,56 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Lite
4
+ module Report
5
+ module Helpers
6
+ module Filters
7
+
8
+ private
9
+
10
+ def except?(delete: false)
11
+ return @data_options.delete(:except) if delete
12
+
13
+ @data_options[:except]
14
+ end
15
+
16
+ def filter?(delete: false)
17
+ only?(delete: delete) || except?(delete: delete)
18
+ end
19
+
20
+ def filter!(row)
21
+ case row.class.name
22
+ when 'Array' then filter_array!(row)
23
+ when 'Hash' then filter_hash!(row)
24
+ end
25
+ end
26
+
27
+ def filter_array!(row)
28
+ if only?
29
+ row.keep_if.with_index { |_, i| @data_options[:only].include?(i) }
30
+ elsif except?
31
+ row.delete_if.with_index { |_, i| @data_options[:except].include?(i) }
32
+ else
33
+ row
34
+ end
35
+ end
36
+
37
+ def filter_hash!(row)
38
+ if only?
39
+ row.keep_if { |key, _| @data_options[:only].include?(key) }
40
+ elsif except?
41
+ row.keep_if { |key, _| @data_options[:except].include?(key) }
42
+ else
43
+ row
44
+ end
45
+ end
46
+
47
+ def only?(delete: false)
48
+ return @data_options.delete(:only) if delete
49
+
50
+ @data_options[:only]
51
+ end
52
+
53
+ end
54
+ end
55
+ end
56
+ end
@@ -0,0 +1,37 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Lite
4
+ module Report
5
+ module Helpers
6
+ module Headers
7
+
8
+ private
9
+
10
+ def header_row?(row)
11
+ return false unless row.respond_to?(:header_row?)
12
+
13
+ row.header_row?
14
+ end
15
+
16
+ def headers?(delete: false)
17
+ return @csv_options.delete(:headers) if delete
18
+
19
+ @csv_options[:headers]
20
+ end
21
+
22
+ def return_headers?(delete: false)
23
+ return @csv_options.delete(:return_headers) if delete
24
+
25
+ @csv_options[:return_headers]
26
+ end
27
+
28
+ def write_headers?(delete: false)
29
+ return @csv_options.delete(:write_headers) if delete
30
+
31
+ @csv_options[:write_headers]
32
+ end
33
+
34
+ end
35
+ end
36
+ end
37
+ end
@@ -0,0 +1,26 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Lite
4
+ module Report
5
+ module Helpers
6
+ module Processors
7
+
8
+ private
9
+
10
+ def process_export_row!(row)
11
+ row = filter!(row) if filter?
12
+ row = values!(row)
13
+ row = encode!(row) if encode?
14
+ row
15
+ end
16
+
17
+ def process_import_row!(row)
18
+ row = filter!(row) if filter?
19
+ row = encode!(row) if encode?
20
+ row
21
+ end
22
+
23
+ end
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,29 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Lite
4
+ module Report
5
+ module Helpers
6
+ module Records
7
+
8
+ private
9
+
10
+ def class_columns(data)
11
+ return data.klass.column_names if ransack_class?(data)
12
+
13
+ data.column_names
14
+ end
15
+
16
+ def klass
17
+ @data_options[:klass]
18
+ end
19
+
20
+ def ransack_class?(data)
21
+ return false unless defined?(Ransack)
22
+
23
+ data.is_a?(Ransack::Search)
24
+ end
25
+
26
+ end
27
+ end
28
+ end
29
+ end