gkosae-spreadshot 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/.gitignore +10 -0
- data/.rspec +1 -0
- data/.yardopts +1 -0
- data/CHANGELOG.md +3 -0
- data/Gemfile +4 -0
- data/Gemfile.lock +47 -0
- data/LICENSE.txt +21 -0
- data/README.md +143 -0
- data/Rakefile +2 -0
- data/bin/console +14 -0
- data/bin/setup +8 -0
- data/lib/spreadshot.rb +17 -0
- data/lib/spreadshot/backends.rb +4 -0
- data/lib/spreadshot/backends/reader_backend.rb +37 -0
- data/lib/spreadshot/backends/ruby_xl_backend.rb +92 -0
- data/lib/spreadshot/backends/smarter_csv_backend.rb +44 -0
- data/lib/spreadshot/reader.rb +132 -0
- data/lib/spreadshot/version.rb +3 -0
- data/spreadshot.gemspec +37 -0
- metadata +149 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: d791d40e930be4758677eaf69b0e06626a6bf3d486f450f613f9f1fe44414024
|
4
|
+
data.tar.gz: 80828c259225f8b85a8596f6a28592add0331763b424d85ec8fb09a748365c2f
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 1ce21cdac4b7f5b2bdcf5cc988b5ecca9e3369871fab128d85ccf05f82fe087991a077525962edd600b3c08aa2eaf4b3c694e5004e0372546d13f6170102651a
|
7
|
+
data.tar.gz: 04504d3c45b1daaa784b4c52b18c46bbdb53420de53ec59e5b6638ee5d237f50f9abb71772570388e47c58908f66c47070fe03c7b45bcbbdd97c60dbf4693999
|
data/.gitignore
ADDED
data/.rspec
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
--require spec_helper
|
data/.yardopts
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
--private
|
data/CHANGELOG.md
ADDED
data/Gemfile
ADDED
data/Gemfile.lock
ADDED
@@ -0,0 +1,47 @@
|
|
1
|
+
PATH
|
2
|
+
remote: .
|
3
|
+
specs:
|
4
|
+
gkosae-spreadshot (0.1.0)
|
5
|
+
rubyXL (~> 3.3.33)
|
6
|
+
smarter_csv (~> 1.2.6)
|
7
|
+
|
8
|
+
GEM
|
9
|
+
remote: https://rubygems.org/
|
10
|
+
specs:
|
11
|
+
byebug (11.0.1)
|
12
|
+
diff-lcs (1.3)
|
13
|
+
mini_portile2 (2.4.0)
|
14
|
+
nokogiri (1.10.4)
|
15
|
+
mini_portile2 (~> 2.4.0)
|
16
|
+
rake (10.5.0)
|
17
|
+
rspec (3.9.0)
|
18
|
+
rspec-core (~> 3.9.0)
|
19
|
+
rspec-expectations (~> 3.9.0)
|
20
|
+
rspec-mocks (~> 3.9.0)
|
21
|
+
rspec-core (3.9.0)
|
22
|
+
rspec-support (~> 3.9.0)
|
23
|
+
rspec-expectations (3.9.0)
|
24
|
+
diff-lcs (>= 1.2.0, < 2.0)
|
25
|
+
rspec-support (~> 3.9.0)
|
26
|
+
rspec-mocks (3.9.0)
|
27
|
+
diff-lcs (>= 1.2.0, < 2.0)
|
28
|
+
rspec-support (~> 3.9.0)
|
29
|
+
rspec-support (3.9.0)
|
30
|
+
rubyXL (3.3.33)
|
31
|
+
nokogiri (>= 1.4.4)
|
32
|
+
rubyzip (>= 1.1.6)
|
33
|
+
rubyzip (2.0.0)
|
34
|
+
smarter_csv (1.2.6)
|
35
|
+
|
36
|
+
PLATFORMS
|
37
|
+
ruby
|
38
|
+
|
39
|
+
DEPENDENCIES
|
40
|
+
bundler (~> 2.0)
|
41
|
+
byebug (~> 11.0)
|
42
|
+
gkosae-spreadshot!
|
43
|
+
rake (~> 10.0)
|
44
|
+
rspec (~> 3.0)
|
45
|
+
|
46
|
+
BUNDLED WITH
|
47
|
+
2.0.2
|
data/LICENSE.txt
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
The MIT License (MIT)
|
2
|
+
|
3
|
+
Copyright (c) 2019 DarkWasp
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
7
|
+
in the Software without restriction, including without limitation the rights
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
10
|
+
furnished to do so, subject to the following conditions:
|
11
|
+
|
12
|
+
The above copyright notice and this permission notice shall be included in
|
13
|
+
all copies or substantial portions of the Software.
|
14
|
+
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
21
|
+
THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,143 @@
|
|
1
|
+
# Spreadshot
|
2
|
+
A Ruby library for reading spreadsheets with support for multiple backends. This is an attempt to:
|
3
|
+
- Provide a uniform interface for reading different formats of spreadsheets.
|
4
|
+
- Reduce the amount of code changed when you decide to switch reader backends for any reason
|
5
|
+
|
6
|
+
[SmarterCSV](https://github.com/tilo/smarter_csv) (for csv files) and [RubyXL](https://github.com/weshatheleopard/rubyXL) (for xlsx files) backends are provided out of the box.
|
7
|
+
|
8
|
+
The name was inspired by the names of [battle chips from Megaman Battle Network 3](https://megaman.fandom.com/wiki/List_of_Mega_Man_Battle_Network_3_Battle_Chips).
|
9
|
+
|
10
|
+
## Installation
|
11
|
+
|
12
|
+
Add this line to your application's Gemfile:
|
13
|
+
|
14
|
+
```ruby
|
15
|
+
gem 'spreadshot'
|
16
|
+
```
|
17
|
+
|
18
|
+
And then execute:
|
19
|
+
|
20
|
+
$ bundle
|
21
|
+
|
22
|
+
Or install it yourself as:
|
23
|
+
|
24
|
+
$ gem install spreadshot
|
25
|
+
|
26
|
+
## Usage
|
27
|
+
|
28
|
+
Require gem with:
|
29
|
+
|
30
|
+
```ruby
|
31
|
+
require 'spreadshot'
|
32
|
+
```
|
33
|
+
|
34
|
+
Read spreadsheet with one of the provided backends
|
35
|
+
```ruby
|
36
|
+
csv_reader = Spreadshot::Reader.new(backend: :smarter_csv)
|
37
|
+
|
38
|
+
begin
|
39
|
+
csv_reader.read(path_to_sample_csv_file) do |row_index, row_data|
|
40
|
+
puts "#{row_index} - #{row_data}"
|
41
|
+
end
|
42
|
+
rescue Spreadshot::ReaderError
|
43
|
+
# Handle error
|
44
|
+
end
|
45
|
+
|
46
|
+
# A cell_index_to_field_mapper must be provided for the RubyXL backend to map values read from a column to a unique key in the yielded hash
|
47
|
+
xlsx_reader = Spreadshot::Reader.new(
|
48
|
+
backend: :ruby_xl,
|
49
|
+
cell_index_to_field_mapper: {0 => :h1, 1 => :h2, 2 => :h3, 3 => :h4}
|
50
|
+
)
|
51
|
+
|
52
|
+
begin
|
53
|
+
xlsx_reader.read(path_to_sample_xlsx_file) do |row_index, row_data|
|
54
|
+
puts "#{row_index} - #{row_data}"
|
55
|
+
end
|
56
|
+
rescue Spreadshot::ReaderError
|
57
|
+
# Handle error
|
58
|
+
end
|
59
|
+
|
60
|
+
# SAMPLE OUTPUT
|
61
|
+
# 2 - {:h1=>11, :h2=>22, :h3=>33, :h4=>44}
|
62
|
+
# 3 - {:h1=>111, :h2=>222, :h3=>333, :h4=>444}
|
63
|
+
# 4 - {:h1=>1111, :h2=>2222, :h3=>3333, :h4=>4444}
|
64
|
+
```
|
65
|
+
|
66
|
+
`row_index` begins from 2 because index 1 is used for headers. But if the spreadsheet does not contain headers then the backend can be configured with `headers: false` to begin reading from index 1 (This is only available for the RubyXL backend. To the best of my knowledge SmarterCSV does not support reading files without headers).
|
67
|
+
|
68
|
+
```ruby
|
69
|
+
xlsx_reader = Spreadshot::Reader.new(
|
70
|
+
backend: :ruby_xl,
|
71
|
+
worksheet_index: 1, # Index of the worksheet to read from (defaults to 0, i.e. the first worksheet)
|
72
|
+
headers: false,
|
73
|
+
cell_index_to_field_mapper: {0 => :h1, 1 => :h2, 2 => :h3, 3 => :h4}
|
74
|
+
)
|
75
|
+
begin
|
76
|
+
xlsx_reader.read(path_to_sample_xlsx_file) do |row_index, row_data|
|
77
|
+
puts "#{row_index} - #{row_data}"
|
78
|
+
end
|
79
|
+
rescue Spreadshot::ReaderError
|
80
|
+
# Handle error
|
81
|
+
end
|
82
|
+
|
83
|
+
# SAMPLE OUTPUT
|
84
|
+
# 1 - {:h1=>11, :h2=>22, :h3=>33, :h4=>44}
|
85
|
+
# 2 - {:h1=>111, :h2=>222, :h3=>333, :h4=>444}
|
86
|
+
# 3 - {:h1=>1111, :h2=>2222, :h3=>3333, :h4=>4444}
|
87
|
+
```
|
88
|
+
|
89
|
+
OR<br/><br/>
|
90
|
+
Read spreadsheet with a custom backend. The custom backend MUST inherit from `Spreadshot::Backends::ReaderBackend` and override `#read`. `#read` MUST yield the index and content(as a Hash) of each row read.<br/><br/>
|
91
|
+
Example:
|
92
|
+
```ruby
|
93
|
+
class SmarterCSVBackend < Spreadshot::Backends::ReaderBackend
|
94
|
+
def initialize(options = {})
|
95
|
+
options ||= {}
|
96
|
+
options[:headers] = true
|
97
|
+
super(options)
|
98
|
+
end
|
99
|
+
|
100
|
+
def read(path_to_spreadsheet)
|
101
|
+
SmarterCSV.process(path_to_spreadsheet) do |row|
|
102
|
+
current_row_data = row.first
|
103
|
+
yield(@current_row_index, current_row_data)
|
104
|
+
@current_row_index += 1
|
105
|
+
end
|
106
|
+
rescue => e
|
107
|
+
raise Spreadshot::ReaderError, e.message
|
108
|
+
end
|
109
|
+
end
|
110
|
+
|
111
|
+
csv_backend = Spreadshot::Backends::SmarterCSVBackend.new
|
112
|
+
csv_reader = Spreadshot::Reader.new(backend: csv_backend)
|
113
|
+
```
|
114
|
+
|
115
|
+
Reader backends can also be switched dynamically with the `#set_backend` method
|
116
|
+
```ruby
|
117
|
+
reader = Spreadshot::Reader.new(backend: :smarter_csv)
|
118
|
+
|
119
|
+
xlsx = Spreadshot::Backends::RubyXLBackend.new(
|
120
|
+
worksheet_index: 0,
|
121
|
+
cell_index_to_field_mapper: {0 => :h1, 1 => :h2, 2 => :h3, 3 => :h4}
|
122
|
+
)
|
123
|
+
reader.set_backend(xlsx)
|
124
|
+
|
125
|
+
#OR
|
126
|
+
|
127
|
+
reader.set_backend(:ruby_xl)
|
128
|
+
```
|
129
|
+
|
130
|
+
|
131
|
+
## Development
|
132
|
+
|
133
|
+
After checking out the repo, run `bin/setup` to install dependencies. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
|
134
|
+
|
135
|
+
To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org).
|
136
|
+
|
137
|
+
## Contributing
|
138
|
+
|
139
|
+
Bug reports and pull requests are welcome on GitHub at https://github.com/gkosae/spreadshot.git
|
140
|
+
|
141
|
+
## License
|
142
|
+
|
143
|
+
The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
|
data/Rakefile
ADDED
data/bin/console
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require "bundler/setup"
|
4
|
+
require "spreadshot"
|
5
|
+
|
6
|
+
# You can add fixtures and/or initialization code here to make experimenting
|
7
|
+
# with your gem easier. You can also use a different console, if you like.
|
8
|
+
|
9
|
+
# (If you use this, don't forget to add pry to your Gemfile!)
|
10
|
+
# require "pry"
|
11
|
+
# Pry.start
|
12
|
+
|
13
|
+
require "irb"
|
14
|
+
IRB.start(__FILE__)
|
data/bin/setup
ADDED
data/lib/spreadshot.rb
ADDED
@@ -0,0 +1,17 @@
|
|
1
|
+
require 'spreadshot/version'
|
2
|
+
require 'spreadshot/backends/reader_backend'
|
3
|
+
require 'spreadshot/backends/ruby_xl_backend'
|
4
|
+
require 'spreadshot/backends/smarter_csv_backend'
|
5
|
+
require 'spreadshot/reader'
|
6
|
+
|
7
|
+
module Spreadshot
|
8
|
+
class SpreadshotError < StandardError
|
9
|
+
def initialize(*args)
|
10
|
+
super(*args)
|
11
|
+
set_backtrace($!.backtrace) if $!
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
class BackendNotFound < SpreadshotError; end
|
16
|
+
class ReaderError < SpreadshotError; end
|
17
|
+
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
module Spreadshot
|
2
|
+
module Backends
|
3
|
+
|
4
|
+
# Base class for all spreadshot reader backends.
|
5
|
+
class ReaderBackend
|
6
|
+
|
7
|
+
# @param [Hash] options
|
8
|
+
# @option options [Boolean] :headers
|
9
|
+
# Specifies whether the spreadsheet to be read contains headers
|
10
|
+
def initialize(options = {})
|
11
|
+
options ||= {}
|
12
|
+
@headers = (options.has_key?(:headers)) ? options[:headers] : true
|
13
|
+
@current_row_index = @headers ? 2 : 1
|
14
|
+
end
|
15
|
+
|
16
|
+
|
17
|
+
|
18
|
+
|
19
|
+
# Reads data from the specified spreadsheet
|
20
|
+
# @note
|
21
|
+
# Must be overriden by subclasses.
|
22
|
+
# Override must raise {Spreadshot::ReaderError Spreadshot::ReaderError} if something goes wrong while reading
|
23
|
+
#
|
24
|
+
#
|
25
|
+
# @param [String] path_to_spreadsheet
|
26
|
+
#
|
27
|
+
# @yield [row_index, row_data]
|
28
|
+
# @yieldparam [Integer] row_index
|
29
|
+
# The index of the current row being read. The first row has an index of 1
|
30
|
+
# @yieldparam [Hash] row_data
|
31
|
+
# A hash representation of the data read from the current row
|
32
|
+
def read(path_to_spreadsheet)
|
33
|
+
raise NotImplementedError
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
@@ -0,0 +1,92 @@
|
|
1
|
+
require 'rubyXL'
|
2
|
+
|
3
|
+
module Spreadshot
|
4
|
+
module Backends
|
5
|
+
|
6
|
+
# Adapter for the RubyXL Gem ({https://github.com/weshatheleopard/rubyXL})
|
7
|
+
class RubyXLBackend < ReaderBackend
|
8
|
+
|
9
|
+
# Returns a new instance of RubyXLBackend (See {ReaderBackend#initialize Spreadshot::ReaderBackends::ReaderBackend})
|
10
|
+
#
|
11
|
+
# @param [Hash] options
|
12
|
+
# @option options [Boolean] :headers
|
13
|
+
# Specifies whether the spreadsheet to be read contains headers.
|
14
|
+
# Defaults to true
|
15
|
+
# @option options [Integer] :worksheet_index
|
16
|
+
# The index of the worksheet to be read. Used for the RubyXL backend.
|
17
|
+
# Defaults to 0
|
18
|
+
# @option options [Hash] :cell_index_to_field_mapper
|
19
|
+
# A hash which maps each cell in a row of the spreadsheet to a key in the
|
20
|
+
# hash created for that row. Must be provided
|
21
|
+
#
|
22
|
+
# @raise [ArgumentError] if cell_index_to_field_mapper option is not provided
|
23
|
+
# @raise [ArgumentError] if cell_index_to_field_mapper option is not a Hash
|
24
|
+
def initialize(options = {})
|
25
|
+
options ||= {}
|
26
|
+
super(options)
|
27
|
+
|
28
|
+
begin
|
29
|
+
@worksheet_index = Integer(options[:worksheet_index])
|
30
|
+
rescue TypeError
|
31
|
+
@worksheet_index = 0
|
32
|
+
end
|
33
|
+
|
34
|
+
begin
|
35
|
+
@cell_index_to_field_mapper = Hash(options[:cell_index_to_field_mapper])
|
36
|
+
rescue TypeError
|
37
|
+
@cell_index_to_field_mapper = options[:cell_index_to_field_mapper]
|
38
|
+
end
|
39
|
+
|
40
|
+
raise ArgumentError, 'cell_index_to_field_mapper is invalid' unless @cell_index_to_field_mapper.is_a?(Hash)
|
41
|
+
raise ArgumentError, 'cell_index_to_field_mapper cannot be empty' if @cell_index_to_field_mapper.empty?
|
42
|
+
end
|
43
|
+
|
44
|
+
|
45
|
+
|
46
|
+
|
47
|
+
# Reads data from the specified spreadsheet
|
48
|
+
# (See {ReaderBackend#read Spreadshot::ReaderBackends::ReaderBackend})
|
49
|
+
#
|
50
|
+
# @param [String] path_to_spreadsheet
|
51
|
+
#
|
52
|
+
# @yield [row_index, row_data]
|
53
|
+
# @yieldparam [Integer] row_index
|
54
|
+
# The index of the current row being read. The first row has an index of 1
|
55
|
+
# @yieldparam [Hash] row_data
|
56
|
+
# A hash representation of the data read from the current row
|
57
|
+
#
|
58
|
+
# @raise [Spreadshot::ReaderError]
|
59
|
+
def read(path_to_spreadsheet)
|
60
|
+
worksheet = RubyXL::Parser.parse(path_to_spreadsheet)[@worksheet_index]
|
61
|
+
headers = @headers
|
62
|
+
|
63
|
+
worksheet.each do |row|
|
64
|
+
if headers
|
65
|
+
headers = false
|
66
|
+
next
|
67
|
+
end
|
68
|
+
|
69
|
+
cell_index = 0
|
70
|
+
current_row_data = {}
|
71
|
+
|
72
|
+
row && row.cells.each do |cell|
|
73
|
+
val = cell && cell.value
|
74
|
+
|
75
|
+
if @cell_index_to_field_mapper[cell_index]
|
76
|
+
current_row_data[@cell_index_to_field_mapper[cell_index]] = val
|
77
|
+
end
|
78
|
+
|
79
|
+
cell_index += 1
|
80
|
+
end
|
81
|
+
|
82
|
+
yield(@current_row_index, current_row_data)
|
83
|
+
@current_row_index += 1
|
84
|
+
end
|
85
|
+
|
86
|
+
return nil
|
87
|
+
rescue => e
|
88
|
+
raise Spreadshot::ReaderError, e.message
|
89
|
+
end
|
90
|
+
end
|
91
|
+
end
|
92
|
+
end
|
@@ -0,0 +1,44 @@
|
|
1
|
+
require 'smarter_csv'
|
2
|
+
|
3
|
+
module Spreadshot
|
4
|
+
module Backends
|
5
|
+
|
6
|
+
# Adapter for the SmarterCSV Gem ({https://github.com/tilo/smarter_csv})
|
7
|
+
class SmarterCSVBackend < ReaderBackend
|
8
|
+
|
9
|
+
# Returns a new instance of SmarterCSVBackend (See {ReaderBackend#initialize Spreadshot::ReaderBackends::ReaderBackend})
|
10
|
+
# @param [Hash] options
|
11
|
+
# @note Ignores :header option
|
12
|
+
def initialize(options = {})
|
13
|
+
options ||= {}
|
14
|
+
options[:headers] = true
|
15
|
+
super(options)
|
16
|
+
end
|
17
|
+
|
18
|
+
|
19
|
+
|
20
|
+
|
21
|
+
# Reads data from the specified CSV file
|
22
|
+
# (See {ReaderBackend#read Spreadshot::ReaderBackends::ReaderBackend})
|
23
|
+
#
|
24
|
+
# @param [String] path_to_spreadsheet
|
25
|
+
#
|
26
|
+
# @yield [row_index, row_data]
|
27
|
+
# @yieldparam [Integer] row_index
|
28
|
+
# The index of the current row being read. The first row has an index of 1
|
29
|
+
# @yieldparam [Hash] row_data
|
30
|
+
# A hash representation of the data read from the current row
|
31
|
+
#
|
32
|
+
# @raise [Spreadshot::ReaderError]
|
33
|
+
def read(path_to_spreadsheet)
|
34
|
+
SmarterCSV.process(path_to_spreadsheet) do |row|
|
35
|
+
current_row_data = row.first
|
36
|
+
yield(@current_row_index, current_row_data)
|
37
|
+
@current_row_index += 1
|
38
|
+
end
|
39
|
+
rescue => e
|
40
|
+
raise Spreadshot::ReaderError, e.message
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
@@ -0,0 +1,132 @@
|
|
1
|
+
module Spreadshot
|
2
|
+
class Reader
|
3
|
+
|
4
|
+
# @param [Hash] options
|
5
|
+
# @option options [Symbol, Spreadshot::ReaderBackend] :backend
|
6
|
+
# The reader backend to use or the id if one of the provided backends
|
7
|
+
# @option options [Hash] :backend_options
|
8
|
+
# Required if one of the provided backends is used
|
9
|
+
# * :headers (Boolean) [true] Specifies whether the spreadsheet to be read contains headers. Will be ignored if the backend doesn't provide this option (E.g. SmarterCSV expects headers)
|
10
|
+
# * :worksheet_index (Integer) [0] The index of the worksheet to be read. Used for the RubyXL backend
|
11
|
+
# * :cell_index_to_field_mapper (Hash<Integer, [String, Symbol]>) A hash which maps each cell in a row of the spreadsheet to a key in the result hash created for that row. Must be provided for the RubyXL backend
|
12
|
+
#
|
13
|
+
# @example
|
14
|
+
# reader = Spreadshot::Reader.new(backend: :smarter_csv)
|
15
|
+
#
|
16
|
+
# reader = Spreadshot::Reader.new(backend: :ruby_xl, worksheet_index: 0, cell_index_to_field_mapper: {0 => :H1, 1 => :H2, 2 => :H3, 3 => :H4})
|
17
|
+
#
|
18
|
+
# xlsx_backend = Spreadshot::Backends::RubyXLBackend.new(worksheet_index: 0, cell_index_to_field_mapper: {0 => :H1, 1 => :H2, 2 => :H3, 3 => :H4})
|
19
|
+
# reader = Spreadshot::Reader.new(backend: xlsx_backend)
|
20
|
+
def initialize(options)
|
21
|
+
set_backend(options[:backend], options[:backend_options])
|
22
|
+
end
|
23
|
+
|
24
|
+
|
25
|
+
|
26
|
+
|
27
|
+
# Set the backend to use
|
28
|
+
#
|
29
|
+
# @param [Symbol, Spreadshot::Backends::ReaderBackend] backend
|
30
|
+
# The new backend or id of one of the provided backends
|
31
|
+
# @param [Hash] backend_options
|
32
|
+
# Required if one of the provided backends is used
|
33
|
+
# @option backend_options [Boolean] :headers
|
34
|
+
# Specifies whether the spreadsheet to be read contains headers.
|
35
|
+
# Will be ignored if the backend doesn't provide this option (E.g. SmarterCSV expects headers)
|
36
|
+
# Defaults to true
|
37
|
+
# @option backend_options [Integer] :worksheet_index
|
38
|
+
# The index of the worksheet to be read. Used for the RubyXL backend.
|
39
|
+
# Defaults to 0
|
40
|
+
# @option backend_options [Hash<Integer, [Symbol, String]>] :cell_index_to_field_mapper
|
41
|
+
# A hash which maps each cell in a row of the spreadsheet to a key in the
|
42
|
+
# result hash created for that row. Used for the RubyXL backend.
|
43
|
+
# Must be provided
|
44
|
+
#
|
45
|
+
# @raise [Spreadshot::BackendNotFound]
|
46
|
+
# If no backend is provided or if one of the provided backends is not specified
|
47
|
+
#
|
48
|
+
# @example
|
49
|
+
# reader = Spreadshot::Reader.new(backend: :ruby_xl, worksheet_index: 0, cell_index_to_field_mapper: {0 => :H1, 1 => :H2, 2 => :H3, 3 => :H4})
|
50
|
+
# csv_backend = Spreadshot::Backends::SmarterCSVBackend.new
|
51
|
+
# reader.set_backend(csv_backend)
|
52
|
+
def set_backend(backend, backend_options = {})
|
53
|
+
@backend = (backend.is_a?(Spreadshot::Backends::ReaderBackend)) ? backend : build_backend(
|
54
|
+
backend,
|
55
|
+
backend_options
|
56
|
+
)
|
57
|
+
|
58
|
+
raise Spreadshot::BackendNotFound if @backend.nil?
|
59
|
+
end
|
60
|
+
|
61
|
+
|
62
|
+
|
63
|
+
|
64
|
+
# Reads data from the specified spreadsheet
|
65
|
+
#
|
66
|
+
# @param [String] path_to_spreadsheet
|
67
|
+
#
|
68
|
+
# @yield [row_index, row_data]
|
69
|
+
# @yieldparam [Integer] row_index
|
70
|
+
# The index of the current row being read. The first row has an index of 1
|
71
|
+
# @yieldparam [Hash] row_data
|
72
|
+
# A hash representation of the data read from the current row
|
73
|
+
#
|
74
|
+
# @note This method delegates actual reading to the backend
|
75
|
+
#
|
76
|
+
# @example
|
77
|
+
# reader = Spreadshot::Reader.new(backend: :ruby_xl, worksheet_index: 0, cell_index_to_field_mapper: {0 => :H1, 1 => :H2, 2 => :H3, 3 => :H4})
|
78
|
+
# reader.read('spreadshot_test.xlsx'){|row_index, row_data| puts "#{row_index} - #{row_data}"}
|
79
|
+
#
|
80
|
+
# Sample output
|
81
|
+
# 2 - {:H1=>11, :H2=>22, :H3=>33, :H4=>44}
|
82
|
+
# 3 - {:H1=>111, :H2=>222, :H3=>333, :H4=>444}
|
83
|
+
# 4 - {:H1=>1111, :H2=>2222, :H3=>3333, :H4=>4444}
|
84
|
+
|
85
|
+
def read(path_to_spreadsheet)
|
86
|
+
@backend.read(path_to_spreadsheet) {|row_index, row_data| yield(row_index, row_data)}
|
87
|
+
end
|
88
|
+
|
89
|
+
|
90
|
+
|
91
|
+
|
92
|
+
private
|
93
|
+
|
94
|
+
# Creates a reader backend using the backend (id) and options/backend_options provided in #initialize or #set_backend
|
95
|
+
#
|
96
|
+
# @param [Symbol] backend_id the id(key) of the desired backend
|
97
|
+
# @param [Hash] backend_options
|
98
|
+
# options to build the backend with
|
99
|
+
# @option backend_options [Boolean] :headers
|
100
|
+
# Specifies whether the spreadsheet to be read contains headers.
|
101
|
+
# Will be ignored if the backend doesn't provide this option (E.g. SmarterCSV expects headers)
|
102
|
+
# Defaults to true
|
103
|
+
# @option backend_options [Integer] :worksheet_index
|
104
|
+
# The index of the worksheet to be read. Used for the RubyXL backend.
|
105
|
+
# Defaults to true
|
106
|
+
# @option backend_options [Hash<Integer, [Symbol, String]>] :cell_index_to_field_mapper
|
107
|
+
# A hash which maps each cell in a row of the spreadsheet to a key in the
|
108
|
+
# result hash created for that row. Used for the RubyXL backend.
|
109
|
+
# Must be provided
|
110
|
+
#
|
111
|
+
# @return [Spreadshot::Backends::ReaderBackend]
|
112
|
+
def build_backend(backend_id, backend_options = {})
|
113
|
+
backend_options ||= {}
|
114
|
+
return provided_backends[backend_id].call(backend_options)
|
115
|
+
rescue NoMethodError
|
116
|
+
return nil
|
117
|
+
end
|
118
|
+
|
119
|
+
|
120
|
+
|
121
|
+
|
122
|
+
# The provided backends
|
123
|
+
#
|
124
|
+
# @return [Hash]
|
125
|
+
def provided_backends
|
126
|
+
{
|
127
|
+
smarter_csv: ->(backend_options){ Spreadshot::Backends::SmarterCSVBackend.new(backend_options) },
|
128
|
+
ruby_xl: ->(backend_options){ Spreadshot::Backends::RubyXLBackend.new(backend_options) },
|
129
|
+
}
|
130
|
+
end
|
131
|
+
end
|
132
|
+
end
|
data/spreadshot.gemspec
ADDED
@@ -0,0 +1,37 @@
|
|
1
|
+
lib = File.expand_path("lib", __dir__)
|
2
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
3
|
+
require "spreadshot/version"
|
4
|
+
|
5
|
+
Gem::Specification.new do |spec|
|
6
|
+
spec.name = "gkosae-spreadshot"
|
7
|
+
spec.version = Spreadshot::VERSION
|
8
|
+
spec.authors = ["George Osae"]
|
9
|
+
spec.email = ["coderwasp@gmail.com"]
|
10
|
+
|
11
|
+
spec.summary = %q{Library for reading spreadsheets with support for multiple backends}
|
12
|
+
spec.homepage = "https://github.com/gkosae/spreadshot.git"
|
13
|
+
spec.license = "MIT"
|
14
|
+
|
15
|
+
spec.metadata["allowed_push_host"] = "https://rubygems.org"
|
16
|
+
|
17
|
+
spec.metadata["homepage_uri"] = spec.homepage
|
18
|
+
spec.metadata["source_code_uri"] = "https://github.com/gkosae/spreadshot.git"
|
19
|
+
# spec.metadata["changelog_uri"] = "TODO: Put your gem's CHANGELOG.md URL here."
|
20
|
+
|
21
|
+
# Specify which files should be added to the gem when it is released.
|
22
|
+
# The `git ls-files -z` loads the files in the RubyGem that have been added into git.
|
23
|
+
spec.files = Dir.chdir(File.expand_path('..', __FILE__)) do
|
24
|
+
`git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
|
25
|
+
end
|
26
|
+
spec.bindir = "exe"
|
27
|
+
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
28
|
+
spec.require_paths = ["lib"]
|
29
|
+
|
30
|
+
spec.add_dependency "smarter_csv", "~> 1.2.6"
|
31
|
+
spec.add_dependency "rubyXL", "~> 3.3.33"
|
32
|
+
|
33
|
+
spec.add_development_dependency "bundler", "~> 2.0"
|
34
|
+
spec.add_development_dependency "rake", "~> 10.0"
|
35
|
+
spec.add_development_dependency "byebug", "~> 11.0"
|
36
|
+
spec.add_development_dependency "rspec", "~> 3.0"
|
37
|
+
end
|
metadata
ADDED
@@ -0,0 +1,149 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: gkosae-spreadshot
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- George Osae
|
8
|
+
autorequire:
|
9
|
+
bindir: exe
|
10
|
+
cert_chain: []
|
11
|
+
date: 2019-10-31 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: smarter_csv
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: 1.2.6
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - "~>"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: 1.2.6
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: rubyXL
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - "~>"
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: 3.3.33
|
34
|
+
type: :runtime
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - "~>"
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: 3.3.33
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: bundler
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - "~>"
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '2.0'
|
48
|
+
type: :development
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - "~>"
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '2.0'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: rake
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - "~>"
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '10.0'
|
62
|
+
type: :development
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - "~>"
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '10.0'
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: byebug
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - "~>"
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: '11.0'
|
76
|
+
type: :development
|
77
|
+
prerelease: false
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - "~>"
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: '11.0'
|
83
|
+
- !ruby/object:Gem::Dependency
|
84
|
+
name: rspec
|
85
|
+
requirement: !ruby/object:Gem::Requirement
|
86
|
+
requirements:
|
87
|
+
- - "~>"
|
88
|
+
- !ruby/object:Gem::Version
|
89
|
+
version: '3.0'
|
90
|
+
type: :development
|
91
|
+
prerelease: false
|
92
|
+
version_requirements: !ruby/object:Gem::Requirement
|
93
|
+
requirements:
|
94
|
+
- - "~>"
|
95
|
+
- !ruby/object:Gem::Version
|
96
|
+
version: '3.0'
|
97
|
+
description:
|
98
|
+
email:
|
99
|
+
- coderwasp@gmail.com
|
100
|
+
executables: []
|
101
|
+
extensions: []
|
102
|
+
extra_rdoc_files: []
|
103
|
+
files:
|
104
|
+
- ".gitignore"
|
105
|
+
- ".rspec"
|
106
|
+
- ".yardopts"
|
107
|
+
- CHANGELOG.md
|
108
|
+
- Gemfile
|
109
|
+
- Gemfile.lock
|
110
|
+
- LICENSE.txt
|
111
|
+
- README.md
|
112
|
+
- Rakefile
|
113
|
+
- bin/console
|
114
|
+
- bin/setup
|
115
|
+
- lib/spreadshot.rb
|
116
|
+
- lib/spreadshot/backends.rb
|
117
|
+
- lib/spreadshot/backends/reader_backend.rb
|
118
|
+
- lib/spreadshot/backends/ruby_xl_backend.rb
|
119
|
+
- lib/spreadshot/backends/smarter_csv_backend.rb
|
120
|
+
- lib/spreadshot/reader.rb
|
121
|
+
- lib/spreadshot/version.rb
|
122
|
+
- spreadshot.gemspec
|
123
|
+
homepage: https://github.com/gkosae/spreadshot.git
|
124
|
+
licenses:
|
125
|
+
- MIT
|
126
|
+
metadata:
|
127
|
+
allowed_push_host: https://rubygems.org
|
128
|
+
homepage_uri: https://github.com/gkosae/spreadshot.git
|
129
|
+
source_code_uri: https://github.com/gkosae/spreadshot.git
|
130
|
+
post_install_message:
|
131
|
+
rdoc_options: []
|
132
|
+
require_paths:
|
133
|
+
- lib
|
134
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
135
|
+
requirements:
|
136
|
+
- - ">="
|
137
|
+
- !ruby/object:Gem::Version
|
138
|
+
version: '0'
|
139
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
140
|
+
requirements:
|
141
|
+
- - ">="
|
142
|
+
- !ruby/object:Gem::Version
|
143
|
+
version: '0'
|
144
|
+
requirements: []
|
145
|
+
rubygems_version: 3.0.6
|
146
|
+
signing_key:
|
147
|
+
specification_version: 4
|
148
|
+
summary: Library for reading spreadsheets with support for multiple backends
|
149
|
+
test_files: []
|