xport 0.1.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.
- checksums.yaml +7 -0
- data/lib/generators/xport/install/install_generator.rb +23 -0
- data/lib/generators/xport/install/templates/migration.rb +23 -0
- data/lib/xport/axlsx.rb +73 -0
- data/lib/xport/cell.rb +7 -0
- data/lib/xport/csv.rb +31 -0
- data/lib/xport/download_presenter.rb +44 -0
- data/lib/xport/downloads_controller_methods.rb +54 -0
- data/lib/xport/export.rb +154 -0
- data/lib/xport/export_builder.rb +51 -0
- data/lib/xport/export_controller_methods.rb +14 -0
- data/lib/xport/version.rb +3 -0
- data/lib/xport.rb +18 -0
- metadata +153 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 6e0b568866d5b2f9c8680d14fe7266ec09b5eb32
|
4
|
+
data.tar.gz: 5051b3e1619135362ec775465583ba1b700621b1
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: ef2450eb7859f679931eb58b9eaf05fa7d97cd90ca16f850b8190885be4d099dd2cd15b2c0c525df6058d21fb2a6cdd451ebb3ef49959e07a529ac2e755818ab
|
7
|
+
data.tar.gz: 01022f1cea1427d8faf3b512759c13a52a86910be75cc64cf44b38b822b8cc0535db9f3726041d038ddcb6453b50366aca1ba1a5d735a3803cbcb169a39b72cb
|
@@ -0,0 +1,23 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Xport
|
4
|
+
module Generators
|
5
|
+
class InstallGenerator < Rails::Generators::Base
|
6
|
+
include Rails::Generators::Migration
|
7
|
+
|
8
|
+
source_root File.expand_path('../templates', __FILE__)
|
9
|
+
|
10
|
+
def self.next_migration_number(dirname)
|
11
|
+
if ActiveRecord::Base.timestamped_migrations
|
12
|
+
Time.new.utc.strftime("%Y%m%d%H%M%S")
|
13
|
+
else
|
14
|
+
format("%.3d", current_migration_number(dirname) + 1)
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
def create_migrations
|
19
|
+
migration_template 'migration.rb', 'db/migrate/create_downloads.rb'
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
class CreateDownloads < ActiveRecord::Migration
|
4
|
+
def up
|
5
|
+
create_table :downloads do |t|
|
6
|
+
t.string :user_id
|
7
|
+
t.string :file_filename
|
8
|
+
t.string :filename
|
9
|
+
t.string :job_id
|
10
|
+
t.string :export_klass_name
|
11
|
+
t.string :export_model_name
|
12
|
+
t.text :query
|
13
|
+
t.integer :records_count
|
14
|
+
t.datetime :exported_at
|
15
|
+
t.string :export_additional_columns, array: true, default: []
|
16
|
+
t.timestamps
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
def down
|
21
|
+
drop_table :downloads
|
22
|
+
end
|
23
|
+
end
|
data/lib/xport/axlsx.rb
ADDED
@@ -0,0 +1,73 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Xport
|
4
|
+
module Axlsx
|
5
|
+
def to_xlsx(&block)
|
6
|
+
formatter = Xport::Axlsx::Formatter.new(self)
|
7
|
+
to_file(formatter, &block)
|
8
|
+
end
|
9
|
+
|
10
|
+
class Formatter
|
11
|
+
attr_reader :export, :workbook, :worksheet
|
12
|
+
|
13
|
+
delegate :builder, to: :export
|
14
|
+
|
15
|
+
def initialize(export)
|
16
|
+
@export = export
|
17
|
+
@package = ::Axlsx::Package.new
|
18
|
+
@workbook = @package.workbook
|
19
|
+
@worksheet = @workbook.add_worksheet
|
20
|
+
|
21
|
+
# Support Numbers and multiline strings in Excel Mac 2011
|
22
|
+
# https://github.com/randym/axlsx/issues/252
|
23
|
+
@package.use_shared_strings = true
|
24
|
+
end
|
25
|
+
|
26
|
+
def to_file
|
27
|
+
@package.to_stream
|
28
|
+
end
|
29
|
+
|
30
|
+
def add_header_row(row)
|
31
|
+
worksheet.add_row row, style: header_style
|
32
|
+
end
|
33
|
+
|
34
|
+
def add_row(row)
|
35
|
+
values = row.map { |v| v.is_a?(Xport::Cell) ? v.value : v }
|
36
|
+
axlsx_row = worksheet.add_row(values, style: styles, types: builder.types)
|
37
|
+
row.each.with_index do |cell, i|
|
38
|
+
next unless cell.is_a?(Xport::Cell)
|
39
|
+
axlsx_cell = axlsx_row.cells[i]
|
40
|
+
axlsx_cell.color = cell.color
|
41
|
+
if cell.comment
|
42
|
+
worksheet.add_comment(
|
43
|
+
ref: axlsx_cell.reference(false),
|
44
|
+
author: 'Conditions',
|
45
|
+
text: cell.comment,
|
46
|
+
visible: false
|
47
|
+
)
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
def merge_header_cells(range)
|
53
|
+
worksheet.merge_cells worksheet.rows.first.cells[range]
|
54
|
+
end
|
55
|
+
|
56
|
+
def column_widths(*widths)
|
57
|
+
worksheet.column_widths(*widths)
|
58
|
+
end
|
59
|
+
|
60
|
+
private
|
61
|
+
|
62
|
+
def styles
|
63
|
+
@styles ||= builder.styles.map do |options|
|
64
|
+
workbook.styles.add_style(options) if options
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
def header_style
|
69
|
+
@header_style ||= workbook.styles.add_style b: true
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
data/lib/xport/cell.rb
ADDED
data/lib/xport/csv.rb
ADDED
@@ -0,0 +1,31 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Xport
|
4
|
+
module CSV
|
5
|
+
def to_csv(&block)
|
6
|
+
formatter = Xport::CSV::Formatter.new(self)
|
7
|
+
to_file(formatter, &block)
|
8
|
+
end
|
9
|
+
|
10
|
+
class Formatter
|
11
|
+
def initialize(export)
|
12
|
+
@io = StringIO.new
|
13
|
+
@csv = ::CSV.new(@io)
|
14
|
+
end
|
15
|
+
|
16
|
+
def to_file
|
17
|
+
@io.rewind
|
18
|
+
@io
|
19
|
+
end
|
20
|
+
|
21
|
+
def add_row(row)
|
22
|
+
values = row.map { |v| v.is_a?(Xport::Cell) ? v.value : v }
|
23
|
+
@csv << values
|
24
|
+
end
|
25
|
+
alias_method :add_header_row, :add_row
|
26
|
+
|
27
|
+
def merge_header_cells(range); end
|
28
|
+
def column_widths(*widths); end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
@@ -0,0 +1,44 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Xport
|
4
|
+
class DownloadPresenter
|
5
|
+
attr_reader :h
|
6
|
+
|
7
|
+
def initialize(download, h)
|
8
|
+
@download = download
|
9
|
+
@h = h
|
10
|
+
end
|
11
|
+
|
12
|
+
def progress_bar(job_id)
|
13
|
+
return unless job_id
|
14
|
+
job = Resque::Plugins::Status::Hash.get(job_id)
|
15
|
+
return unless job
|
16
|
+
|
17
|
+
case job.status
|
18
|
+
when Resque::Plugins::Status::STATUS_COMPLETED
|
19
|
+
nil
|
20
|
+
when Resque::Plugins::Status::STATUS_QUEUED
|
21
|
+
progress_bar_pending
|
22
|
+
else
|
23
|
+
h.content_tag(:div, class: 'progress', data: { component: 'Future.ProgressBar' }) do
|
24
|
+
h.content_tag(:div, class: 'progress-bar', style: "width: #{job.pct_complete}%") do
|
25
|
+
"#{job.pct_complete}% #{job.message}"
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
def progress_bar_pending
|
32
|
+
message = I18n.translate(
|
33
|
+
'helpers.progress_bar.please_wait_pending',
|
34
|
+
count: Resque.info[:pending]
|
35
|
+
)
|
36
|
+
|
37
|
+
h.content_tag(:div, class: 'progress', data: { component: 'Future.ProgressBar' }) do
|
38
|
+
h.content_tag(:div, class: 'progress-bar progress-bar-pending', style: 'width: 100%') do
|
39
|
+
h.content_tag(:span, message)
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
@@ -0,0 +1,54 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Xport
|
4
|
+
module DownloadsControllerMethods
|
5
|
+
extend ActiveSupport::Concern
|
6
|
+
|
7
|
+
included do
|
8
|
+
before_action :set_download, only: %i(show update destroy)
|
9
|
+
before_action :set_downloads, only: :index
|
10
|
+
end
|
11
|
+
|
12
|
+
def index; end
|
13
|
+
|
14
|
+
def show
|
15
|
+
respond_to do |format|
|
16
|
+
format.html do
|
17
|
+
if !request.xhr? && @download.file?
|
18
|
+
redirect_to format: @download.type
|
19
|
+
else
|
20
|
+
render 'show'
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
format.any(:xlsx, :csv) do
|
25
|
+
send_data @download.file.read, filename: @download.filename
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
def update
|
31
|
+
@download.schedule_export!
|
32
|
+
redirect_to @download
|
33
|
+
end
|
34
|
+
|
35
|
+
def destroy
|
36
|
+
@download.destroy
|
37
|
+
redirect_to action: 'index'
|
38
|
+
end
|
39
|
+
|
40
|
+
private
|
41
|
+
|
42
|
+
def resource_class
|
43
|
+
controller_path.classify.constantize
|
44
|
+
end
|
45
|
+
|
46
|
+
def set_download
|
47
|
+
@download = resource_class.find(params[:id])
|
48
|
+
end
|
49
|
+
|
50
|
+
def set_downloads
|
51
|
+
@downloads = resource_class.page(params[:page])
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
data/lib/xport/export.rb
ADDED
@@ -0,0 +1,154 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Xport
|
4
|
+
class Export
|
5
|
+
attr_reader :workbook, :objects, :builder
|
6
|
+
|
7
|
+
class_attribute :builder_block
|
8
|
+
|
9
|
+
def self.columns(&block)
|
10
|
+
self.builder_block = block
|
11
|
+
end
|
12
|
+
|
13
|
+
def initialize(objects = [])
|
14
|
+
@objects = objects
|
15
|
+
@builder = Xport::ExportBuilder.new(self, &builder_block)
|
16
|
+
end
|
17
|
+
|
18
|
+
def to_file(formatter = nil, &block)
|
19
|
+
preload!
|
20
|
+
# TODO: There shouldn't be a default formatter
|
21
|
+
formatter ||= Xport::Axlsx::Formatter.new(self)
|
22
|
+
write_contents(formatter, &block)
|
23
|
+
formatter.to_file
|
24
|
+
end
|
25
|
+
|
26
|
+
def object_class
|
27
|
+
self.class.name.sub(/Export/, '').singularize.constantize
|
28
|
+
end
|
29
|
+
|
30
|
+
# TODO: Extract to xport-downloads?
|
31
|
+
def download(filename:, user: nil)
|
32
|
+
return unless objects.respond_to?(:to_sql)
|
33
|
+
download = download_class.new
|
34
|
+
download.user = user
|
35
|
+
download.export_klass_name = self.class.name
|
36
|
+
|
37
|
+
if objects.respond_to?(:model)
|
38
|
+
download.export_model_name = objects.model.name
|
39
|
+
end
|
40
|
+
if respond_to?(:additional_columns)
|
41
|
+
download.export_additional_columns = additional_columns
|
42
|
+
end
|
43
|
+
# TODO: Remove `unprepared_statement` call when `to_sql` is fixed
|
44
|
+
# https://github.com/rails/rails/issues/18379
|
45
|
+
object_class.connection.unprepared_statement do
|
46
|
+
download.query = objects.to_sql
|
47
|
+
end
|
48
|
+
download.filename = filename
|
49
|
+
download.save!
|
50
|
+
download.schedule_export!
|
51
|
+
download
|
52
|
+
end
|
53
|
+
|
54
|
+
def download_class
|
55
|
+
module_name = self.class.to_s.deconstantize
|
56
|
+
if module_name.present?
|
57
|
+
"#{module_name}::Download".constantize
|
58
|
+
else
|
59
|
+
Download
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
private
|
64
|
+
|
65
|
+
def preload!; end
|
66
|
+
|
67
|
+
def write_contents(formatter, &block)
|
68
|
+
write_header(formatter)
|
69
|
+
write_body(formatter, &block)
|
70
|
+
write_widths(formatter)
|
71
|
+
end
|
72
|
+
|
73
|
+
def write_header(formatter)
|
74
|
+
if builder.grouped?
|
75
|
+
group_row = []
|
76
|
+
builder.groups_with_offset_and_colspan.each do |group, offset, colspan|
|
77
|
+
group_row << human_attribute_name(group)
|
78
|
+
(colspan - 1).times do
|
79
|
+
group_row << nil
|
80
|
+
end
|
81
|
+
end
|
82
|
+
formatter.add_header_row group_row
|
83
|
+
|
84
|
+
builder.groups_with_offset_and_colspan.each do |group, offset, colspan|
|
85
|
+
colspan -= 1
|
86
|
+
formatter.merge_header_cells(offset..offset + colspan)
|
87
|
+
end
|
88
|
+
end
|
89
|
+
formatter.add_header_row header_row
|
90
|
+
end
|
91
|
+
|
92
|
+
def write_body(formatter)
|
93
|
+
each_object do |object, rownum|
|
94
|
+
yield rownum, objects.size if block_given?
|
95
|
+
formatter.add_row object_row(object)
|
96
|
+
end
|
97
|
+
end
|
98
|
+
|
99
|
+
def write_widths(formatter)
|
100
|
+
formatter.column_widths(*builder.widths)
|
101
|
+
end
|
102
|
+
|
103
|
+
def find_in_batches?
|
104
|
+
false
|
105
|
+
end
|
106
|
+
|
107
|
+
def each_object(&block)
|
108
|
+
if find_in_batches?
|
109
|
+
objects.find_each.with_index(&block)
|
110
|
+
else
|
111
|
+
objects.each_with_index(&block)
|
112
|
+
end
|
113
|
+
end
|
114
|
+
|
115
|
+
def header_row
|
116
|
+
builder.headers.map do |name|
|
117
|
+
human_attribute_name(name)
|
118
|
+
end
|
119
|
+
end
|
120
|
+
|
121
|
+
def human_attribute_name(name)
|
122
|
+
return if name.to_s.start_with?('empty')
|
123
|
+
|
124
|
+
klass = object_class
|
125
|
+
case name
|
126
|
+
when String
|
127
|
+
name
|
128
|
+
when Symbol
|
129
|
+
klass.human_attribute_name(name)
|
130
|
+
end
|
131
|
+
end
|
132
|
+
|
133
|
+
def object_row(object)
|
134
|
+
builder.columns.map.with_index do |name, index|
|
135
|
+
block = builder.blocks[index]
|
136
|
+
if block
|
137
|
+
value = instance_exec(object, &block)
|
138
|
+
elsif respond_to?(name, true)
|
139
|
+
value = send(name, object)
|
140
|
+
else
|
141
|
+
value = object.send(name)
|
142
|
+
if respond_to?("convert_#{name}", true)
|
143
|
+
value = send("convert_#{name}", value)
|
144
|
+
end
|
145
|
+
end
|
146
|
+
value
|
147
|
+
end
|
148
|
+
end
|
149
|
+
|
150
|
+
def helper
|
151
|
+
ApplicationController.helpers
|
152
|
+
end
|
153
|
+
end
|
154
|
+
end
|
@@ -0,0 +1,51 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Xport
|
4
|
+
class ExportBuilder
|
5
|
+
attr_reader :export, :columns, :headers, :groups, :styles, :types, :widths, :blocks
|
6
|
+
|
7
|
+
def initialize(export, &block)
|
8
|
+
@export = export
|
9
|
+
@columns = []
|
10
|
+
@headers = []
|
11
|
+
@groups = []
|
12
|
+
@styles = []
|
13
|
+
@types = []
|
14
|
+
@widths = []
|
15
|
+
@blocks = []
|
16
|
+
instance_exec(export, &block)
|
17
|
+
end
|
18
|
+
|
19
|
+
def column(name, type: nil, style: nil, width: nil, header: nil, group: nil, &block)
|
20
|
+
columns << name
|
21
|
+
headers << (header || name)
|
22
|
+
groups << group
|
23
|
+
types << type
|
24
|
+
styles << style
|
25
|
+
widths << width
|
26
|
+
blocks << block
|
27
|
+
end
|
28
|
+
|
29
|
+
def grouped?
|
30
|
+
groups.any?
|
31
|
+
end
|
32
|
+
|
33
|
+
def groups_with_offset_and_colspan
|
34
|
+
offset = 0
|
35
|
+
colspan = 1
|
36
|
+
[].tap do |result|
|
37
|
+
groups.each do |group|
|
38
|
+
last = result.last
|
39
|
+
# check if current group is same as last group
|
40
|
+
if last && last[0] == group
|
41
|
+
# if group is the same, update colspan
|
42
|
+
last[2] += 1
|
43
|
+
else
|
44
|
+
result << [group, offset, colspan]
|
45
|
+
end
|
46
|
+
offset += 1
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
@@ -0,0 +1,14 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Xport
|
4
|
+
module ExportControllerMethods
|
5
|
+
def xport_export(export, filename:)
|
6
|
+
download = export.download(filename: filename, user: current_user)
|
7
|
+
if download
|
8
|
+
redirect_to download
|
9
|
+
else
|
10
|
+
send_data export.to_file.read, filename: filename
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
data/lib/xport.rb
ADDED
@@ -0,0 +1,18 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'active_support/core_ext/class/attribute'
|
4
|
+
require 'active_support/core_ext/module/delegation'
|
5
|
+
require 'active_support/concern'
|
6
|
+
|
7
|
+
require 'xport/version'
|
8
|
+
require 'xport/export'
|
9
|
+
require 'xport/export_builder'
|
10
|
+
require 'xport/cell'
|
11
|
+
require 'xport/downloads_controller_methods'
|
12
|
+
require 'xport/export_controller_methods'
|
13
|
+
require 'xport/download_presenter'
|
14
|
+
require 'xport/axlsx'
|
15
|
+
require 'xport/csv'
|
16
|
+
|
17
|
+
module Xport
|
18
|
+
end
|
metadata
ADDED
@@ -0,0 +1,153 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: xport
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Janis Vitols
|
8
|
+
- Edgars Beigarts
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2017-08-18 00:00:00.000000000 Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: activesupport
|
16
|
+
requirement: !ruby/object:Gem::Requirement
|
17
|
+
requirements:
|
18
|
+
- - ">="
|
19
|
+
- !ruby/object:Gem::Version
|
20
|
+
version: '0'
|
21
|
+
type: :runtime
|
22
|
+
prerelease: false
|
23
|
+
version_requirements: !ruby/object:Gem::Requirement
|
24
|
+
requirements:
|
25
|
+
- - ">="
|
26
|
+
- !ruby/object:Gem::Version
|
27
|
+
version: '0'
|
28
|
+
- !ruby/object:Gem::Dependency
|
29
|
+
name: bundler
|
30
|
+
requirement: !ruby/object:Gem::Requirement
|
31
|
+
requirements:
|
32
|
+
- - "~>"
|
33
|
+
- !ruby/object:Gem::Version
|
34
|
+
version: '1.5'
|
35
|
+
type: :development
|
36
|
+
prerelease: false
|
37
|
+
version_requirements: !ruby/object:Gem::Requirement
|
38
|
+
requirements:
|
39
|
+
- - "~>"
|
40
|
+
- !ruby/object:Gem::Version
|
41
|
+
version: '1.5'
|
42
|
+
- !ruby/object:Gem::Dependency
|
43
|
+
name: rake
|
44
|
+
requirement: !ruby/object:Gem::Requirement
|
45
|
+
requirements:
|
46
|
+
- - "~>"
|
47
|
+
- !ruby/object:Gem::Version
|
48
|
+
version: '10.1'
|
49
|
+
type: :development
|
50
|
+
prerelease: false
|
51
|
+
version_requirements: !ruby/object:Gem::Requirement
|
52
|
+
requirements:
|
53
|
+
- - "~>"
|
54
|
+
- !ruby/object:Gem::Version
|
55
|
+
version: '10.1'
|
56
|
+
- !ruby/object:Gem::Dependency
|
57
|
+
name: rspec
|
58
|
+
requirement: !ruby/object:Gem::Requirement
|
59
|
+
requirements:
|
60
|
+
- - "~>"
|
61
|
+
- !ruby/object:Gem::Version
|
62
|
+
version: '3.6'
|
63
|
+
type: :development
|
64
|
+
prerelease: false
|
65
|
+
version_requirements: !ruby/object:Gem::Requirement
|
66
|
+
requirements:
|
67
|
+
- - "~>"
|
68
|
+
- !ruby/object:Gem::Version
|
69
|
+
version: '3.6'
|
70
|
+
- !ruby/object:Gem::Dependency
|
71
|
+
name: simplecov
|
72
|
+
requirement: !ruby/object:Gem::Requirement
|
73
|
+
requirements:
|
74
|
+
- - "~>"
|
75
|
+
- !ruby/object:Gem::Version
|
76
|
+
version: '0.8'
|
77
|
+
type: :development
|
78
|
+
prerelease: false
|
79
|
+
version_requirements: !ruby/object:Gem::Requirement
|
80
|
+
requirements:
|
81
|
+
- - "~>"
|
82
|
+
- !ruby/object:Gem::Version
|
83
|
+
version: '0.8'
|
84
|
+
- !ruby/object:Gem::Dependency
|
85
|
+
name: axlsx
|
86
|
+
requirement: !ruby/object:Gem::Requirement
|
87
|
+
requirements:
|
88
|
+
- - ">="
|
89
|
+
- !ruby/object:Gem::Version
|
90
|
+
version: '0'
|
91
|
+
type: :development
|
92
|
+
prerelease: false
|
93
|
+
version_requirements: !ruby/object:Gem::Requirement
|
94
|
+
requirements:
|
95
|
+
- - ">="
|
96
|
+
- !ruby/object:Gem::Version
|
97
|
+
version: '0'
|
98
|
+
- !ruby/object:Gem::Dependency
|
99
|
+
name: saxlsx
|
100
|
+
requirement: !ruby/object:Gem::Requirement
|
101
|
+
requirements:
|
102
|
+
- - ">="
|
103
|
+
- !ruby/object:Gem::Version
|
104
|
+
version: '0'
|
105
|
+
type: :development
|
106
|
+
prerelease: false
|
107
|
+
version_requirements: !ruby/object:Gem::Requirement
|
108
|
+
requirements:
|
109
|
+
- - ">="
|
110
|
+
- !ruby/object:Gem::Version
|
111
|
+
version: '0'
|
112
|
+
description:
|
113
|
+
email:
|
114
|
+
executables: []
|
115
|
+
extensions: []
|
116
|
+
extra_rdoc_files: []
|
117
|
+
files:
|
118
|
+
- lib/generators/xport/install/install_generator.rb
|
119
|
+
- lib/generators/xport/install/templates/migration.rb
|
120
|
+
- lib/xport.rb
|
121
|
+
- lib/xport/axlsx.rb
|
122
|
+
- lib/xport/cell.rb
|
123
|
+
- lib/xport/csv.rb
|
124
|
+
- lib/xport/download_presenter.rb
|
125
|
+
- lib/xport/downloads_controller_methods.rb
|
126
|
+
- lib/xport/export.rb
|
127
|
+
- lib/xport/export_builder.rb
|
128
|
+
- lib/xport/export_controller_methods.rb
|
129
|
+
- lib/xport/version.rb
|
130
|
+
homepage:
|
131
|
+
licenses: []
|
132
|
+
metadata: {}
|
133
|
+
post_install_message:
|
134
|
+
rdoc_options: []
|
135
|
+
require_paths:
|
136
|
+
- lib
|
137
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
138
|
+
requirements:
|
139
|
+
- - ">="
|
140
|
+
- !ruby/object:Gem::Version
|
141
|
+
version: '0'
|
142
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
143
|
+
requirements:
|
144
|
+
- - ">="
|
145
|
+
- !ruby/object:Gem::Version
|
146
|
+
version: '0'
|
147
|
+
requirements: []
|
148
|
+
rubyforge_project:
|
149
|
+
rubygems_version: 2.6.11
|
150
|
+
signing_key:
|
151
|
+
specification_version: 4
|
152
|
+
summary: CSV/Excel exports with own DSL and background jobs
|
153
|
+
test_files: []
|