spreadsheet_goodies 0.0.4 → 0.0.5
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +63 -13
- data/builds/spreadsheet_goodies-0.0.4.gem +0 -0
- data/lib/spreadsheet_goodies/abstract_base_worksheet.rb +39 -0
- data/lib/spreadsheet_goodies/excel/workbook_builder.rb +80 -0
- data/lib/spreadsheet_goodies/excel/worksheet.rb +53 -0
- data/lib/spreadsheet_goodies/excel.rb +11 -0
- data/lib/spreadsheet_goodies/google_drive/connector.rb +104 -0
- data/lib/spreadsheet_goodies/google_drive/worksheet.rb +68 -0
- data/lib/spreadsheet_goodies/google_drive.rb +12 -0
- data/lib/spreadsheet_goodies/row.rb +33 -0
- data/lib/spreadsheet_goodies/version.rb +1 -1
- data/lib/spreadsheet_goodies.rb +7 -4
- data/spreadsheet_goodies.gemspec +5 -5
- metadata +16 -12
- data/LICENSE.txt +0 -24
- data/lib/spreadsheet_goodies/excel_workbook_builder.rb +0 -78
- data/lib/spreadsheet_goodies/excel_worksheet.rb +0 -68
- data/lib/spreadsheet_goodies/excel_worksheet_row.rb +0 -30
- data/lib/spreadsheet_goodies/google_drive_connector.rb +0 -93
- data/lib/spreadsheet_goodies/google_drive_worksheet.rb +0 -68
- data/lib/spreadsheet_goodies/google_drive_worksheet_row.rb +0 -23
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 1cb1da443d319f91e093023601d1688081db8344
|
4
|
+
data.tar.gz: 10d6c084df8ae3da6ba1a1322805750d52191a3d
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: ec886820ca483030f181f1d82542660aa9f54a898f9d0c97478648937c7e4ea9f44cf5086a508efe4442acc4ed6f002b941e8c4f3680912fe77ee031f95a1078
|
7
|
+
data.tar.gz: 434ed1a593759e605e34f18f345245a78ea7c208c64f9f9a1f9dbdd3d1f719f093b6d638a3dfb15e47b206aaecfb3965da89e0ad37bdf8f969b7fa1529267fe9
|
data/README.md
CHANGED
@@ -1,11 +1,11 @@
|
|
1
1
|
# SpreadsheetGoodies
|
2
2
|
|
3
|
-
SpreadsheetGoodies is a collection of tools to help work with spreadsheets in
|
4
|
-
Excel and Google Spreadhseets formats. It relies heavily on other gems to make
|
5
|
-
the actual work of reading and writing to spreadsheet documents. It main
|
3
|
+
SpreadsheetGoodies is a collection of tools to help work with spreadsheets in
|
4
|
+
Excel and Google Spreadhseets formats. It relies heavily on other gems to make
|
5
|
+
the actual work of reading and writing to spreadsheet documents. It main
|
6
6
|
features are:
|
7
7
|
|
8
|
-
* Read a spreadseet as an array of arrays to allow aceessing its data without
|
8
|
+
* Read a spreadseet as an array of arrays to allow aceessing its data without
|
9
9
|
using the original document
|
10
10
|
* Access a row's elements using the column titles as keys"
|
11
11
|
|
@@ -28,24 +28,75 @@ Or install it yourself as:
|
|
28
28
|
## Usage
|
29
29
|
|
30
30
|
Read a Google Spreadsheet:
|
31
|
-
```
|
32
|
-
|
33
|
-
|
31
|
+
```ruby
|
32
|
+
sheet = SpreadsheetGoodies::GoogleDrive.read_worksheet(
|
33
|
+
spreadsheet_key: '1UC43X6aZwlWPCnn...', # required,
|
34
|
+
worksheet_title: 'sheet1', # optional, first worksheet is loaded if not specified
|
35
|
+
)
|
34
36
|
```
|
35
37
|
|
36
38
|
Read an Excel workbook:
|
37
|
-
```
|
38
|
-
sheet = SpreadsheetGoodies::
|
39
|
+
```ruby
|
40
|
+
sheet = SpreadsheetGoodies::Excel.read_worksheet(
|
41
|
+
file_pathname: '~/workbook.xlsx', # required,
|
42
|
+
worksheet_title_or_index: 'sheet1', # optional, first worksheet is loaded if not specified
|
43
|
+
)
|
39
44
|
```
|
40
45
|
|
41
|
-
Iterate over every data row (i.e., all but the header row) and print the value
|
42
|
-
of a column titled 'Total':
|
43
|
-
```
|
46
|
+
Iterate over every data row (i.e., all but the header row) and print the value
|
47
|
+
of a column titled 'Total':
|
48
|
+
```ruby
|
44
49
|
sheet.data_rows.each do |row|
|
45
50
|
puts "#{row.row_number} -- #{row['Total']}"
|
46
51
|
end
|
47
52
|
```
|
48
53
|
|
54
|
+
Writing values to cells (only available for GoogleDrive adapter right now):
|
55
|
+
```ruby
|
56
|
+
row = sheet[0]
|
57
|
+
row[0] = 'First cell'
|
58
|
+
row[1] = 'Second cell'
|
59
|
+
sheet.commit_writes! # changes are applied to real spreadsheet
|
60
|
+
```
|
61
|
+
|
62
|
+
## Logging in to Google Drive
|
63
|
+
If you need to access a spreadsheet on Google Drive that is not publicly accessible,
|
64
|
+
you are required to setup an authentication method. Currently, there are two available
|
65
|
+
authentication methods.
|
66
|
+
|
67
|
+
### OAuth2
|
68
|
+
To setup OAuth2, first you must configure your Google client id and a client secret
|
69
|
+
like the example below. If you don't have a client id yet, you must create a project
|
70
|
+
and enable the GoogleDrive API at https://console.developers.google.com. Then you
|
71
|
+
need to create a OAuth client id.
|
72
|
+
```ruby
|
73
|
+
SpreadsheetGoodies.configure do |config|
|
74
|
+
config.login_method = :oauth2
|
75
|
+
config.google_client_id = '1012345678904-fdks82jfhe8ojdks7285fj4pnqiejrnbt.apps.googleusercontent.com' # put your real client id here
|
76
|
+
config.client_secret = 'Aa-Ku8C-askjfAYKkdjf9ssnf' # put your real secret here
|
77
|
+
end
|
78
|
+
```
|
79
|
+
|
80
|
+
Then run your code. You will be prompted to make the authorization process to obtain
|
81
|
+
a refresh token:
|
82
|
+
```
|
83
|
+
1. Open this page:
|
84
|
+
https://accounts.google.com/o/oauth2/auth?access_type=offline&client_id=1012345678904-fdks82jfhe8ojdks7285fj4pnqiejrnbt.apps.googleusercontent.com&redirect_uri=urn:ietf:wg:oauth:2.0:oob&response_type=code&scope=https://www.googleapis.com/auth/drive%20https://spreadsheets.google.com/feeds/
|
85
|
+
|
86
|
+
2. Enter the authorization code shown in the page: 4/LADQHhpk7x27BMeP2tIEe_pKuTJmJmZhWoRcBhBmFTVRqSEtcap7Z6s
|
87
|
+
|
88
|
+
Congratulations! Your refresh token is: 1/c9JDKAUF83_4SPqNc8ldQWe9TdXOxqXvMJJPtmDA2k
|
89
|
+
Set the refresh_token in your SpreadsheetGoodies configuration and run your code again
|
90
|
+
```
|
91
|
+
|
92
|
+
### Service Accounts
|
93
|
+
```ruby
|
94
|
+
SpreadsheetGoodies.configure do |config|
|
95
|
+
config.login_method = :service_account
|
96
|
+
config.service_account_key_json = '...'
|
97
|
+
end
|
98
|
+
```
|
99
|
+
|
49
100
|
## Contributing
|
50
101
|
|
51
102
|
Bug reports and pull requests are welcome on GitHub at https://github.com/ricardo-jasinski/spreadsheet_goodies.
|
@@ -54,4 +105,3 @@ Bug reports and pull requests are welcome on GitHub at https://github.com/ricard
|
|
54
105
|
## License
|
55
106
|
|
56
107
|
The gem is available as open source under the terms of the [Unlicense](http://unlicense.org/UNLICENSE).
|
57
|
-
|
Binary file
|
@@ -0,0 +1,39 @@
|
|
1
|
+
|
2
|
+
# Base class for all worksheets
|
3
|
+
module SpreadsheetGoodies
|
4
|
+
class AbstractBaseWorksheet
|
5
|
+
attr_reader :rows, :header_row
|
6
|
+
|
7
|
+
def [](index)
|
8
|
+
@rows[index]
|
9
|
+
end
|
10
|
+
|
11
|
+
# Return only the rows that contain data (excludes the header rows)
|
12
|
+
def data_rows
|
13
|
+
@rows[@num_header_rows..-1]
|
14
|
+
end
|
15
|
+
|
16
|
+
# Finds and returns the first row that contains cell_value at the given column
|
17
|
+
def find_row_by_column_value(column_title, cell_value)
|
18
|
+
data_rows.each do |row|
|
19
|
+
return row if row[column_title] == cell_value
|
20
|
+
end
|
21
|
+
|
22
|
+
nil
|
23
|
+
end
|
24
|
+
|
25
|
+
# Writes to a given cell identified by row and column indexes (they start at 1)
|
26
|
+
# This method should be overriden by worksheets that wish to implement writes.
|
27
|
+
# Usually this method is not called directly by the gem user, but rather from
|
28
|
+
# the modified row itself
|
29
|
+
def write_to_cell(row_index, col_index, value)
|
30
|
+
raise 'writes are not implemented for this type of worksheet'
|
31
|
+
end
|
32
|
+
|
33
|
+
# Some adapters (like GoogleDrive) require writes to be committed to actually
|
34
|
+
# make the changes on the spreadsheet
|
35
|
+
def commit_writes!
|
36
|
+
raise 'this kind of worksheet does not require writes to be committed'
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
@@ -0,0 +1,80 @@
|
|
1
|
+
require 'axlsx'
|
2
|
+
|
3
|
+
# A set of methods to help create and format Excel workbooks
|
4
|
+
module SpreadsheetGoodies::Excel
|
5
|
+
class WorkbookBuilder
|
6
|
+
attr_reader :current_sheet
|
7
|
+
|
8
|
+
def initialize(output_file_pathname)
|
9
|
+
@output_file_pathname = output_file_pathname
|
10
|
+
@axlsx_package = Axlsx::Package.new
|
11
|
+
end
|
12
|
+
|
13
|
+
# The underlying Axlsx::Workbook object
|
14
|
+
def workbook
|
15
|
+
@axlsx_package.workbook
|
16
|
+
end
|
17
|
+
|
18
|
+
def add_worksheet(sheet_name)
|
19
|
+
@current_sheet = @workbook.add_worksheet(name: sheet_name)
|
20
|
+
setup_current_sheet_styles
|
21
|
+
freeze_top_row
|
22
|
+
@current_sheet
|
23
|
+
end
|
24
|
+
|
25
|
+
# Add a row to the current sheet using the data row style
|
26
|
+
def add_data_row(row_values)
|
27
|
+
@current_sheet.add_row(row_values, style: @data_row_style)
|
28
|
+
end
|
29
|
+
|
30
|
+
# Add a row to the current sheet using the header row style
|
31
|
+
def add_header_row(row_values)
|
32
|
+
@current_sheet.add_row(row_values, style: @header_row_style)
|
33
|
+
end
|
34
|
+
|
35
|
+
# Add filter and sorting controls to a sheet.
|
36
|
+
def setup_auto_filter(sheet=nil)
|
37
|
+
worksheet = sheet || @current_sheet
|
38
|
+
top_left_cell_label = worksheet.dimension.first_cell_reference
|
39
|
+
bottom_right_cell_label = worksheet.dimension.last_cell_reference
|
40
|
+
filter_range = "#{top_left_cell_label}:#{bottom_right_cell_label}"
|
41
|
+
worksheet.auto_filter = filter_range
|
42
|
+
end
|
43
|
+
|
44
|
+
def write_to_file
|
45
|
+
@axlsx_package.serialize(@output_file_pathname)
|
46
|
+
end
|
47
|
+
|
48
|
+
def freeze_top_row
|
49
|
+
@current_sheet.sheet_view.pane do |pane|
|
50
|
+
pane.top_left_cell = 'A2'
|
51
|
+
pane.state = :frozen_split
|
52
|
+
pane.y_split = 1
|
53
|
+
pane.active_pane = :bottom_right
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
private
|
58
|
+
|
59
|
+
def setup_current_sheet_styles
|
60
|
+
@header_row_style = @current_sheet.styles.add_style(
|
61
|
+
alignment: {horizontal: :center, vertical: :center},
|
62
|
+
font_name: 'Calibri',
|
63
|
+
bg_color: 'FFDDDDDD',
|
64
|
+
b: true,
|
65
|
+
)
|
66
|
+
|
67
|
+
@header_row_sodexo_style = @current_sheet.styles.add_style(
|
68
|
+
alignment: {horizontal: :center, vertical: :center},
|
69
|
+
font_name: 'Calibri',
|
70
|
+
bg_color: '002060',
|
71
|
+
fg_color: 'FFFFFF',
|
72
|
+
b: true,
|
73
|
+
)
|
74
|
+
|
75
|
+
@data_row_style = @current_sheet.styles.add_style(
|
76
|
+
font_name: 'Calibri',
|
77
|
+
)
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|
@@ -0,0 +1,53 @@
|
|
1
|
+
require_relative '../abstract_base_worksheet'
|
2
|
+
require_relative '../row'
|
3
|
+
|
4
|
+
# A cached copy of an Excel worksheet (a single workbook "tab"), stored as an
|
5
|
+
# array of arrays. Individual cells can be accessed by column title, e.g.:
|
6
|
+
# worksheet[0]['A column title']
|
7
|
+
module SpreadsheetGoodies::Excel
|
8
|
+
class Worksheet < SpreadsheetGoodies::AbstractBaseWorksheet
|
9
|
+
attr_reader :workbook, :worksheet
|
10
|
+
|
11
|
+
# @param workbook_file_pathname [String] Full path and filename to Excel workbook document
|
12
|
+
# @param worksheet_title_or_index [String|Integer] Sheet name or index (zero-based)
|
13
|
+
# within the workbook. Optional; if unspecified, the first sheet will be used.
|
14
|
+
# @param num_header_rows [Integer] Number of rows at the top of the sheet that
|
15
|
+
# contain headers or stuff other than data. Optional; if unspecified, assumes
|
16
|
+
# that a single top row contains the header and all rows below are data.
|
17
|
+
def initialize(workbook_file_pathname, worksheet_title_or_index=0, num_header_rows=1)
|
18
|
+
@worksheet_title = worksheet_title_or_index
|
19
|
+
@num_header_rows = num_header_rows
|
20
|
+
|
21
|
+
@workbook = case workbook_file_pathname.to_s
|
22
|
+
when /\.xls[^x]/ then Roo::Excel.new(workbook_file_pathname, file_warning: :ignore)
|
23
|
+
when /\.xlsx/ then Roo::Excelx.new(workbook_file_pathname, file_warning: :ignore)
|
24
|
+
end
|
25
|
+
|
26
|
+
@worksheet = @workbook.sheet(worksheet_title_or_index)
|
27
|
+
|
28
|
+
@header_row = @worksheet.row(num_header_rows)
|
29
|
+
|
30
|
+
# Reads all the worksheet rows, one at a time, using Workshete#row (note: reading
|
31
|
+
# them all at once using Worksheet#parse didn't work because the first row
|
32
|
+
# was missed some times.)
|
33
|
+
rows = (1..@worksheet.last_row).map {|row_number| @worksheet.row(row_number) }
|
34
|
+
|
35
|
+
# Create the rows cache, made of instances of ExcelWorksheetRow
|
36
|
+
@rows = rows.collect.with_index do |row, index|
|
37
|
+
SpreadsheetGoodies::Row.new(@header_row, index+1, self, *row)
|
38
|
+
end
|
39
|
+
|
40
|
+
self
|
41
|
+
end
|
42
|
+
|
43
|
+
def add_row(row_data)
|
44
|
+
last_row_number = @rows.count
|
45
|
+
@rows << SpreadsheetGoodies::Row.new(@header_row, last_row_number+1, self, *row_data)
|
46
|
+
end
|
47
|
+
|
48
|
+
def spreadsheet
|
49
|
+
@workbook
|
50
|
+
end
|
51
|
+
|
52
|
+
end
|
53
|
+
end
|
@@ -0,0 +1,11 @@
|
|
1
|
+
|
2
|
+
module SpreadsheetGoodies::Excel
|
3
|
+
|
4
|
+
def self.read_worksheet(file_pathname:, worksheet_title_or_index:0, num_header_rows:1)
|
5
|
+
Worksheet.new(file_pathname, worksheet_title_or_index, num_header_rows)
|
6
|
+
end
|
7
|
+
|
8
|
+
end
|
9
|
+
|
10
|
+
# loads all files in excel folder
|
11
|
+
Dir[File.join(File.dirname(__FILE__), "excel/**/*.rb")].each { |f| require f }
|
@@ -0,0 +1,104 @@
|
|
1
|
+
require 'google_drive'
|
2
|
+
require 'googleauth'
|
3
|
+
|
4
|
+
module SpreadsheetGoodies::GoogleDrive
|
5
|
+
class Connector
|
6
|
+
attr_reader :logger, :session
|
7
|
+
|
8
|
+
def initialize
|
9
|
+
@logger = Logger.new(STDOUT)
|
10
|
+
@session = log_into_google_drive
|
11
|
+
raise 'Session not found!' unless @session
|
12
|
+
end
|
13
|
+
|
14
|
+
# Reads a GoogleDrive::Spreadsheet object from Google Drive, using the
|
15
|
+
# google_drive gem. Documentation for this class can be found here:
|
16
|
+
# https://www.rubydoc.info/github/gimite/google-drive-ruby/GoogleDrive/Spreadsheet
|
17
|
+
def read_worksheet(spreadsheet_key, worksheet_title=nil)
|
18
|
+
puts "Reading sheet '#{worksheet_title}' from Google Drive..."
|
19
|
+
spreadsheet = @session.spreadsheet_by_key(spreadsheet_key)
|
20
|
+
|
21
|
+
if worksheet_title
|
22
|
+
worksheet = spreadsheet.worksheet_by_title(worksheet_title)
|
23
|
+
if worksheet.nil?
|
24
|
+
raise "Worksheet named '#{worksheet_title}' not found in spreadsheet."
|
25
|
+
end
|
26
|
+
else
|
27
|
+
worksheet = spreadsheet.worksheets.first
|
28
|
+
end
|
29
|
+
|
30
|
+
worksheet
|
31
|
+
end
|
32
|
+
|
33
|
+
def read_worksheet_as_string(spreadsheet_key, worksheet_title)
|
34
|
+
worksheet = read_worksheet(spreadsheet_key, worksheet_title)
|
35
|
+
contents = worksheet.export_as_string.force_encoding('utf-8')
|
36
|
+
puts 'Spreadsheet read successfully.'
|
37
|
+
contents
|
38
|
+
end
|
39
|
+
|
40
|
+
private
|
41
|
+
|
42
|
+
def log_into_google_drive
|
43
|
+
case SpreadsheetGoodies.configuration.login_method
|
44
|
+
when :service_account then log_into_google_drive_via_service_account
|
45
|
+
when :oauth2 then log_into_google_drive_via_oauth2
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
# Authenticate with Google Drive via OAuth2.
|
50
|
+
# Your OAuth2 ids can be accessed at https://console.developers.google.com/apis/credentials,
|
51
|
+
# logged with your Google account in your custom project. The keys are at
|
52
|
+
# 'API manager' > 'Credentials'. CLIENT_ID and CLIENT_SECRET are available
|
53
|
+
# from the credentials page. The REFRESH_TOKEN must be obtained uncommenting
|
54
|
+
# some rows from the method below and obtaining an access_token via a browser
|
55
|
+
# logged in to your google account.
|
56
|
+
def log_into_google_drive_via_oauth2
|
57
|
+
credentials = Google::Auth::UserRefreshCredentials.new(
|
58
|
+
client_id: SpreadsheetGoodies.configuration.google_client_id,
|
59
|
+
client_secret: SpreadsheetGoodies.configuration.client_secret,
|
60
|
+
scope: [
|
61
|
+
'https://www.googleapis.com/auth/drive',
|
62
|
+
'https://spreadsheets.google.com/feeds/',
|
63
|
+
],
|
64
|
+
redirect_uri: 'urn:ietf:wg:oauth:2.0:oob'
|
65
|
+
)
|
66
|
+
|
67
|
+
# if has refresh_token, logs in
|
68
|
+
if SpreadsheetGoodies.configuration.refresh_token
|
69
|
+
credentials.refresh_token = SpreadsheetGoodies.configuration.refresh_token
|
70
|
+
|
71
|
+
# if refresh_token is missing, prompts user to obtain it
|
72
|
+
else
|
73
|
+
print("1. Open this page:\n%s\n\n" % credentials.authorization_uri)
|
74
|
+
print("2. Enter the authorization code shown in the page: ")
|
75
|
+
credentials.code = $stdin.gets.chomp
|
76
|
+
credentials.fetch_access_token!
|
77
|
+
print("\nCongratulations! Your refresh token is: #{credentials.refresh_token}\n")
|
78
|
+
print("Set the refresh_token in your SpreadsheetGoodies configuration and run your code again\n")
|
79
|
+
exit(0)
|
80
|
+
end
|
81
|
+
|
82
|
+
begin
|
83
|
+
credentials.fetch_access_token!
|
84
|
+
rescue Faraday::ConnectionFailed
|
85
|
+
logger.info 'Error logging into Google Drive. Is your internet connection down?'
|
86
|
+
exit
|
87
|
+
end
|
88
|
+
|
89
|
+
session = GoogleDrive::Session.from_credentials(credentials)
|
90
|
+
end
|
91
|
+
|
92
|
+
# Authenticate with Google Drive via a service account.
|
93
|
+
# Your service accounts can be accessed at https://console.developers.google.com/apis/credentials,
|
94
|
+
# logged with your Google account in your custom project.
|
95
|
+
# The service accounts are at 'IAM and administrator' > 'Service accounts'.
|
96
|
+
# The keys are at 'API manager' > 'Credentials'.
|
97
|
+
def log_into_google_drive_via_service_account
|
98
|
+
session = GoogleDrive::Session.from_service_account_key(
|
99
|
+
StringIO.new(SpreadsheetGoodies.configuration.service_account_key_json)
|
100
|
+
)
|
101
|
+
session
|
102
|
+
end
|
103
|
+
end
|
104
|
+
end
|
@@ -0,0 +1,68 @@
|
|
1
|
+
require 'csv'
|
2
|
+
require_relative '../abstract_base_worksheet'
|
3
|
+
require_relative '../row'
|
4
|
+
|
5
|
+
# A cached copy of a Google Spreadsheets worksheet (i.e., a single workbook "tab"),
|
6
|
+
# Individual cells of a row can be accessed by column title.
|
7
|
+
# Example:
|
8
|
+
# worksheet[0]['A column title']
|
9
|
+
module SpreadsheetGoodies::GoogleDrive
|
10
|
+
class Worksheet < SpreadsheetGoodies::AbstractBaseWorksheet
|
11
|
+
# @param spreadsheet_key [String] Spreadsheet identifier, which can be retrieved
|
12
|
+
# from the spreasheet's url
|
13
|
+
# @param worksheet_title_or_index [String] Sheet name; if unspecified, the
|
14
|
+
# first sheet will be used.
|
15
|
+
# @param num_header_rows [Integer] Number of rows at the top of the sheet that
|
16
|
+
# contain headers or stuff other than data. Optional; if unspecified, assumes
|
17
|
+
# that a single top row contains the header and all rows below are data.
|
18
|
+
def initialize(spreadsheet_key, worksheet_title=nil, num_header_rows=1)
|
19
|
+
@spreadsheet_key = spreadsheet_key
|
20
|
+
@worksheet_title = worksheet_title
|
21
|
+
@num_header_rows = num_header_rows
|
22
|
+
|
23
|
+
read_from_google_drive
|
24
|
+
end
|
25
|
+
|
26
|
+
# Writes to a given cell identified by row and column indexes (they start at 1)
|
27
|
+
# @override
|
28
|
+
def write_to_cell(row_index, col_index, value)
|
29
|
+
underlying_adapter_worksheet[row_index, col_index] = value
|
30
|
+
end
|
31
|
+
|
32
|
+
# Commit writes so they are propagated to the real spreadsheet
|
33
|
+
# @override
|
34
|
+
def commit_writes!
|
35
|
+
underlying_adapter_worksheet.save
|
36
|
+
end
|
37
|
+
|
38
|
+
private
|
39
|
+
|
40
|
+
# Reads sheet contents and caches it into instance variables to so that it
|
41
|
+
# can be accessed later without accessing Google Drive.
|
42
|
+
def read_from_google_drive
|
43
|
+
worksheet_contents = underlying_adapter_worksheet.export_as_string.force_encoding('utf-8')
|
44
|
+
|
45
|
+
rows = CSV::parse(worksheet_contents)
|
46
|
+
|
47
|
+
if SpreadsheetGoodies.configuration.strip_values_on_read
|
48
|
+
rows = rows.map do |row|
|
49
|
+
row.map {|element| element.try(:strip) }
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
@header_row = rows[@num_header_rows-1]
|
54
|
+
@rows = rows.collect.with_index do |row, index|
|
55
|
+
SpreadsheetGoodies::Row.new(@header_row, index+1, self, *row)
|
56
|
+
end
|
57
|
+
|
58
|
+
self
|
59
|
+
end
|
60
|
+
|
61
|
+
# Reads a GoogleDrive::Spreadsheet object from Google Drive, using the
|
62
|
+
# google_drive gem. Documentation for this class can be found here:
|
63
|
+
# https://www.rubydoc.info/github/gimite/google-drive-ruby/GoogleDrive/Spreadsheet
|
64
|
+
def underlying_adapter_worksheet
|
65
|
+
@underlying_adapter_worksheet ||= Connector.new.read_worksheet(@spreadsheet_key, @worksheet_title)
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
@@ -0,0 +1,12 @@
|
|
1
|
+
|
2
|
+
module SpreadsheetGoodies::GoogleDrive
|
3
|
+
|
4
|
+
# Accesses GoogleDrive and returns a SpreadsheetGoodies::GoogleDrive::Worksheet
|
5
|
+
def self.read_worksheet(spreadsheet_key:, worksheet_title:nil, num_header_rows:1)
|
6
|
+
Worksheet.new(spreadsheet_key, worksheet_title, num_header_rows)
|
7
|
+
end
|
8
|
+
|
9
|
+
end
|
10
|
+
|
11
|
+
# loads all files in google_drive folder
|
12
|
+
Dir[File.join(File.dirname(__FILE__), "google_drive/**/*.rb")].each { |f| require f }
|
@@ -0,0 +1,33 @@
|
|
1
|
+
module SpreadsheetGoodies
|
2
|
+
|
3
|
+
|
4
|
+
# Sobrecarrega método [] da Array para permitir acessar células passando
|
5
|
+
# o título da coluna como índice. Ex: row['Data formal do pedido']
|
6
|
+
class Row < Array
|
7
|
+
attr_reader :header_row, :row_number, :parent_worksheet
|
8
|
+
|
9
|
+
def initialize(header_row, sheet_row_number, parent_worksheet, *args)
|
10
|
+
@header_row = header_row
|
11
|
+
@row_number = sheet_row_number
|
12
|
+
@parent_worksheet = parent_worksheet
|
13
|
+
super(args)
|
14
|
+
end
|
15
|
+
|
16
|
+
def [](locator)
|
17
|
+
cell_index = (locator.is_a?(String) ? @header_row.index(locator) : locator)
|
18
|
+
|
19
|
+
# queries local cache only
|
20
|
+
super(cell_index)
|
21
|
+
end
|
22
|
+
|
23
|
+
def []=(locator, value)
|
24
|
+
cell_index = (locator.is_a?(String) ? @header_row.index(locator) : locator)
|
25
|
+
|
26
|
+
# propagates change to real worksheet
|
27
|
+
@parent_worksheet.write_to_cell(@row_number, cell_index+1, value)
|
28
|
+
|
29
|
+
# updates local cache
|
30
|
+
super(cell_index, value)
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
data/lib/spreadsheet_goodies.rb
CHANGED
@@ -1,7 +1,10 @@
|
|
1
|
+
module SpreadsheetGoodies
|
2
|
+
|
3
|
+
end
|
4
|
+
|
1
5
|
require 'spreadsheet_goodies/version'
|
2
|
-
require 'spreadsheet_goodies/
|
3
|
-
require 'spreadsheet_goodies/
|
4
|
-
require 'spreadsheet_goodies/excel_worksheet'
|
6
|
+
require 'spreadsheet_goodies/google_drive'
|
7
|
+
require 'spreadsheet_goodies/excel'
|
5
8
|
require 'roo'
|
6
9
|
|
7
10
|
module SpreadsheetGoodies
|
@@ -31,4 +34,4 @@ module SpreadsheetGoodies
|
|
31
34
|
end
|
32
35
|
end
|
33
36
|
|
34
|
-
end
|
37
|
+
end
|
data/spreadsheet_goodies.gemspec
CHANGED
@@ -6,13 +6,13 @@ require 'spreadsheet_goodies/version'
|
|
6
6
|
Gem::Specification.new do |gemspec|
|
7
7
|
gemspec.name = 'spreadsheet_goodies'
|
8
8
|
gemspec.version = SpreadsheetGoodies::VERSION
|
9
|
-
gemspec.authors = ['Ricardo Jasinski']
|
10
|
-
gemspec.email = ['jasinski@solvis.com.br']
|
9
|
+
gemspec.authors = ['Ricardo Jasinski', 'Henrique Gubert']
|
10
|
+
gemspec.email = ['jasinski@solvis.com.br', 'guberthenrique@hotmail.com']
|
11
11
|
|
12
12
|
gemspec.summary = "SpreadsheetGoodies is a collection of tools to help work " +
|
13
|
-
"with Excel and Google Drive
|
13
|
+
"with Excel and Google Drive spreadsheets."
|
14
14
|
gemspec.description = "SpreadsheetGoodies is a collection of tools to help work " +
|
15
|
-
"with Excel and Google Drive
|
15
|
+
"with Excel and Google Drive spreadsheets. It relies " +
|
16
16
|
"on other gems to do the actual work of reading and writing to " +
|
17
17
|
"spreadsheet documents. It main features are:"
|
18
18
|
" * Read a spreadseet to an array of arrays, to allow accessing its data " +
|
@@ -38,4 +38,4 @@ Gem::Specification.new do |gemspec|
|
|
38
38
|
gemspec.add_dependency 'csv', '>= 3.0.0'
|
39
39
|
gemspec.add_dependency 'roo', '>= 1.13.2'
|
40
40
|
|
41
|
-
end
|
41
|
+
end
|
metadata
CHANGED
@@ -1,14 +1,15 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: spreadsheet_goodies
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.5
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Ricardo Jasinski
|
8
|
+
- Henrique Gubert
|
8
9
|
autorequire:
|
9
10
|
bindir: exe
|
10
11
|
cert_chain: []
|
11
|
-
date: 2018-
|
12
|
+
date: 2018-08-17 00:00:00.000000000 Z
|
12
13
|
dependencies:
|
13
14
|
- !ruby/object:Gem::Dependency
|
14
15
|
name: bundler
|
@@ -109,10 +110,11 @@ dependencies:
|
|
109
110
|
- !ruby/object:Gem::Version
|
110
111
|
version: 1.13.2
|
111
112
|
description: 'SpreadsheetGoodies is a collection of tools to help work with Excel
|
112
|
-
and Google Drive
|
113
|
+
and Google Drive spreadsheets. It relies on other gems to do the actual work of
|
113
114
|
reading and writing to spreadsheet documents. It main features are:'
|
114
115
|
email:
|
115
116
|
- jasinski@solvis.com.br
|
117
|
+
- guberthenrique@hotmail.com
|
116
118
|
executables: []
|
117
119
|
extensions: []
|
118
120
|
extra_rdoc_files: []
|
@@ -124,7 +126,6 @@ files:
|
|
124
126
|
- ".travis.yml"
|
125
127
|
- Gemfile
|
126
128
|
- LICENSE
|
127
|
-
- LICENSE.txt
|
128
129
|
- README.md
|
129
130
|
- Rakefile
|
130
131
|
- bin/console
|
@@ -132,13 +133,16 @@ files:
|
|
132
133
|
- builds/spreadsheet_goodies-0.0.1.gem
|
133
134
|
- builds/spreadsheet_goodies-0.0.2.gem
|
134
135
|
- builds/spreadsheet_goodies-0.0.3.gem
|
136
|
+
- builds/spreadsheet_goodies-0.0.4.gem
|
135
137
|
- lib/spreadsheet_goodies.rb
|
136
|
-
- lib/spreadsheet_goodies/
|
137
|
-
- lib/spreadsheet_goodies/
|
138
|
-
- lib/spreadsheet_goodies/
|
139
|
-
- lib/spreadsheet_goodies/
|
140
|
-
- lib/spreadsheet_goodies/
|
141
|
-
- lib/spreadsheet_goodies/
|
138
|
+
- lib/spreadsheet_goodies/abstract_base_worksheet.rb
|
139
|
+
- lib/spreadsheet_goodies/excel.rb
|
140
|
+
- lib/spreadsheet_goodies/excel/workbook_builder.rb
|
141
|
+
- lib/spreadsheet_goodies/excel/worksheet.rb
|
142
|
+
- lib/spreadsheet_goodies/google_drive.rb
|
143
|
+
- lib/spreadsheet_goodies/google_drive/connector.rb
|
144
|
+
- lib/spreadsheet_goodies/google_drive/worksheet.rb
|
145
|
+
- lib/spreadsheet_goodies/row.rb
|
142
146
|
- lib/spreadsheet_goodies/version.rb
|
143
147
|
- spreadsheet_goodies.gemspec
|
144
148
|
homepage: https://github.com/ricardo-jasinski/spreadsheet_goodies
|
@@ -162,9 +166,9 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
162
166
|
version: '0'
|
163
167
|
requirements: []
|
164
168
|
rubyforge_project:
|
165
|
-
rubygems_version: 2.6.
|
169
|
+
rubygems_version: 2.6.8
|
166
170
|
signing_key:
|
167
171
|
specification_version: 4
|
168
172
|
summary: SpreadsheetGoodies is a collection of tools to help work with Excel and Google
|
169
|
-
Drive
|
173
|
+
Drive spreadsheets.
|
170
174
|
test_files: []
|
data/LICENSE.txt
DELETED
@@ -1,24 +0,0 @@
|
|
1
|
-
This is free and unencumbered software released into the public domain.
|
2
|
-
|
3
|
-
Anyone is free to copy, modify, publish, use, compile, sell, or
|
4
|
-
distribute this software, either in source code form or as a compiled
|
5
|
-
binary, for any purpose, commercial or non-commercial, and by any
|
6
|
-
means.
|
7
|
-
|
8
|
-
In jurisdictions that recognize copyright laws, the author or authors
|
9
|
-
of this software dedicate any and all copyright interest in the
|
10
|
-
software to the public domain. We make this dedication for the benefit
|
11
|
-
of the public at large and to the detriment of our heirs and
|
12
|
-
successors. We intend this dedication to be an overt act of
|
13
|
-
relinquishment in perpetuity of all present and future rights to this
|
14
|
-
software under copyright law.
|
15
|
-
|
16
|
-
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
17
|
-
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
18
|
-
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
19
|
-
IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
|
20
|
-
OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
|
21
|
-
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
22
|
-
OTHER DEALINGS IN THE SOFTWARE.
|
23
|
-
|
24
|
-
For more information, please refer to <http://unlicense.org>
|
@@ -1,78 +0,0 @@
|
|
1
|
-
require 'axlsx'
|
2
|
-
|
3
|
-
# A set of methods to help create and format Excel workbooks
|
4
|
-
class SpreadsheetGoodies::ExcelWorkbookBuilder
|
5
|
-
attr_reader :current_sheet
|
6
|
-
|
7
|
-
def initialize(output_file_pathname)
|
8
|
-
@output_file_pathname = output_file_pathname
|
9
|
-
@axlsx_package = Axlsx::Package.new
|
10
|
-
end
|
11
|
-
|
12
|
-
# The underlying Axlsx::Workbook object
|
13
|
-
def workbook
|
14
|
-
@axlsx_package.workbook
|
15
|
-
end
|
16
|
-
|
17
|
-
def add_worksheet(sheet_name)
|
18
|
-
@current_sheet = @workbook.add_worksheet(name: sheet_name)
|
19
|
-
setup_current_sheet_styles
|
20
|
-
freeze_top_row
|
21
|
-
@current_sheet
|
22
|
-
end
|
23
|
-
|
24
|
-
# Add a row to the current sheet using the data row style
|
25
|
-
def add_data_row(row_values)
|
26
|
-
@current_sheet.add_row(row_values, style: @data_row_style)
|
27
|
-
end
|
28
|
-
|
29
|
-
# Add a row to the current sheet using the header row style
|
30
|
-
def add_header_row(row_values)
|
31
|
-
@current_sheet.add_row(row_values, style: @header_row_style)
|
32
|
-
end
|
33
|
-
|
34
|
-
# Add filter and sorting controls to a sheet.
|
35
|
-
def setup_auto_filter(sheet=nil)
|
36
|
-
worksheet = sheet || @current_sheet
|
37
|
-
top_left_cell_label = worksheet.dimension.first_cell_reference
|
38
|
-
bottom_right_cell_label = worksheet.dimension.last_cell_reference
|
39
|
-
filter_range = "#{top_left_cell_label}:#{bottom_right_cell_label}"
|
40
|
-
worksheet.auto_filter = filter_range
|
41
|
-
end
|
42
|
-
|
43
|
-
def write_to_file
|
44
|
-
@axlsx_package.serialize(@output_file_pathname)
|
45
|
-
end
|
46
|
-
|
47
|
-
def freeze_top_row
|
48
|
-
@current_sheet.sheet_view.pane do |pane|
|
49
|
-
pane.top_left_cell = 'A2'
|
50
|
-
pane.state = :frozen_split
|
51
|
-
pane.y_split = 1
|
52
|
-
pane.active_pane = :bottom_right
|
53
|
-
end
|
54
|
-
end
|
55
|
-
|
56
|
-
private
|
57
|
-
|
58
|
-
def setup_current_sheet_styles
|
59
|
-
@header_row_style = @current_sheet.styles.add_style(
|
60
|
-
alignment: {horizontal: :center, vertical: :center},
|
61
|
-
font_name: 'Calibri',
|
62
|
-
bg_color: 'FFDDDDDD',
|
63
|
-
b: true,
|
64
|
-
)
|
65
|
-
|
66
|
-
@header_row_sodexo_style = @current_sheet.styles.add_style(
|
67
|
-
alignment: {horizontal: :center, vertical: :center},
|
68
|
-
font_name: 'Calibri',
|
69
|
-
bg_color: '002060',
|
70
|
-
fg_color: 'FFFFFF',
|
71
|
-
b: true,
|
72
|
-
)
|
73
|
-
|
74
|
-
@data_row_style = @current_sheet.styles.add_style(
|
75
|
-
font_name: 'Calibri',
|
76
|
-
)
|
77
|
-
end
|
78
|
-
end
|
@@ -1,68 +0,0 @@
|
|
1
|
-
require_relative 'excel_worksheet_row'
|
2
|
-
|
3
|
-
# A cached copy of an Excel worksheet (a single workbook "tab"), stored as an
|
4
|
-
# array of arrays. Individual cells can be accessed by column title, e.g.:
|
5
|
-
# worksheet[0]['A column title']
|
6
|
-
class SpreadsheetGoodies::ExcelWorksheet
|
7
|
-
attr_reader :rows, :workbook, :worksheet
|
8
|
-
|
9
|
-
# @param workbook_file_pathname [String] Full path and filename to Excel workbook document
|
10
|
-
# @param worksheet_title_or_index [String|Integer] Sheet name or index (zero-based)
|
11
|
-
# within the workbook. Optional; if unspecified, the first sheet will be used.
|
12
|
-
# @param num_header_rows [Integer] Number of rows at the top of the sheet that
|
13
|
-
# contain headers or stuff other than data. Optional; if unspecified, assumes
|
14
|
-
# that a single top row contains the header and all rows below are data.
|
15
|
-
def initialize(workbook_file_pathname, worksheet_title_or_index=0, num_header_rows=1)
|
16
|
-
@worksheet_title = worksheet_title_or_index
|
17
|
-
@num_header_rows = num_header_rows
|
18
|
-
|
19
|
-
@workbook = case workbook_file_pathname.to_s
|
20
|
-
when /\.xls[^x]/ then Roo::Excel.new(workbook_file_pathname, file_warning: :ignore)
|
21
|
-
when /\.xlsx/ then Roo::Excelx.new(workbook_file_pathname, file_warning: :ignore)
|
22
|
-
end
|
23
|
-
|
24
|
-
@worksheet = @workbook.sheet(worksheet_title_or_index)
|
25
|
-
|
26
|
-
@header_row = @worksheet.row(num_header_rows)
|
27
|
-
|
28
|
-
# Reads all the worksheet rows, one at a time, using Workshete#row (note: reading
|
29
|
-
# them all at once using Worksheet#parse didn't work because the first row
|
30
|
-
# was missed some times.)
|
31
|
-
rows = (1..@worksheet.last_row).map {|row_number| @worksheet.row(row_number) }
|
32
|
-
|
33
|
-
# Create the rows cache, made of instances of ExcelWorksheetRow
|
34
|
-
@rows = rows.collect.with_index do |row, index|
|
35
|
-
ExcelWorksheetRow.new(@header_row, index+1, *row)
|
36
|
-
end
|
37
|
-
|
38
|
-
self
|
39
|
-
end
|
40
|
-
|
41
|
-
def [](index)
|
42
|
-
@rows[index]
|
43
|
-
end
|
44
|
-
|
45
|
-
# Return only the rows that contain data (excludes the header rows)
|
46
|
-
def data_rows
|
47
|
-
@rows[@num_header_rows..-1]
|
48
|
-
end
|
49
|
-
|
50
|
-
# Finds and returns the first row that contains cell_value at the given column
|
51
|
-
def find_row_by_column_value(column_title, cell_value)
|
52
|
-
data_rows.each do |row|
|
53
|
-
return row if row[column_title] == cell_value
|
54
|
-
end
|
55
|
-
|
56
|
-
nil
|
57
|
-
end
|
58
|
-
|
59
|
-
def add_row(row_data)
|
60
|
-
last_row_number = @rows.count
|
61
|
-
@rows << ExcelWorksheetRow.new(@header_row, last_row_number+1, *row_data)
|
62
|
-
end
|
63
|
-
|
64
|
-
def spreadsheet
|
65
|
-
@workbook
|
66
|
-
end
|
67
|
-
|
68
|
-
end
|
@@ -1,30 +0,0 @@
|
|
1
|
-
class SpreadsheetGoodies::ExcelWorksheet
|
2
|
-
|
3
|
-
# Overload Array#[] to allow reading a cell's contents using its column title
|
4
|
-
# as index, e.g.: row['Column Title']
|
5
|
-
class ::ExcelWorksheetRow < Array
|
6
|
-
attr_reader :header_row, :row_number
|
7
|
-
|
8
|
-
# @param header_row [Array] The header cells of the sheet from were the row was taken
|
9
|
-
# @param sheet_row_number [Integer] The original row number of the row in the
|
10
|
-
# sheet from where the row was taken. Row numebrs follow the spreadshet convention,
|
11
|
-
# i.e., starting from 1.
|
12
|
-
def initialize(header_row, sheet_row_number, *args)
|
13
|
-
@header_row = header_row
|
14
|
-
@row_number = sheet_row_number
|
15
|
-
super(args)
|
16
|
-
end
|
17
|
-
|
18
|
-
# @param locator [Integer|String] The index of a row element. Can be a string
|
19
|
-
# (a column title) or an integer (starting at 0 for the first cell).
|
20
|
-
# @return [String]
|
21
|
-
def [](locator)
|
22
|
-
if locator.is_a?(String)
|
23
|
-
return self[ @header_row.index(locator) ]
|
24
|
-
else
|
25
|
-
return super(locator)
|
26
|
-
end
|
27
|
-
end
|
28
|
-
end
|
29
|
-
|
30
|
-
end
|
@@ -1,93 +0,0 @@
|
|
1
|
-
require 'google_drive'
|
2
|
-
require 'googleauth'
|
3
|
-
|
4
|
-
class SpreadsheetGoodies::GoogleDriveConnector
|
5
|
-
attr_reader :logger, :session
|
6
|
-
|
7
|
-
def initialize
|
8
|
-
@logger = Logger.new(STDOUT)
|
9
|
-
@session = log_into_google_drive
|
10
|
-
raise 'Session not found!' unless @session
|
11
|
-
end
|
12
|
-
|
13
|
-
def log_into_google_drive
|
14
|
-
case SpreadsheetGoodies.configuration.login_method
|
15
|
-
when :service_account then log_into_google_drive_via_service_account
|
16
|
-
when :oauth2 then log_into_google_drive_via_oauth2
|
17
|
-
end
|
18
|
-
end
|
19
|
-
|
20
|
-
def read_worksheet(spreadsheet_key, worksheet_title=nil)
|
21
|
-
puts "Reading sheet '#{worksheet_title}' from Google Drive..."
|
22
|
-
spreadsheet = @session.spreadsheet_by_key(spreadsheet_key)
|
23
|
-
|
24
|
-
if worksheet_title
|
25
|
-
worksheet = spreadsheet.worksheet_by_title(worksheet_title)
|
26
|
-
if worksheet.nil?
|
27
|
-
raise "Worksheet named '#{worksheet_title}' not found in spreadsheet."
|
28
|
-
end
|
29
|
-
else
|
30
|
-
worksheet = spreadsheet.worksheets.first
|
31
|
-
end
|
32
|
-
|
33
|
-
worksheet
|
34
|
-
end
|
35
|
-
|
36
|
-
def read_worksheet_as_string(spreadsheet_key, worksheet_title)
|
37
|
-
worksheet = read_worksheet(spreadsheet_key, worksheet_title)
|
38
|
-
contents = worksheet.export_as_string.force_encoding('utf-8')
|
39
|
-
puts 'Spreadhseet read successfully.'
|
40
|
-
contents
|
41
|
-
end
|
42
|
-
|
43
|
-
private
|
44
|
-
|
45
|
-
# Authenticate with Google Drive via OAuth2.
|
46
|
-
# Your OAuth2 ids can be accessed at https://console.developers.google.com/apis/credentials,
|
47
|
-
# logged with your Google account in your custom project. The keys are at
|
48
|
-
# 'API manager' > 'Credentials'. CLIENT_ID and CLIENT_SECRET are available
|
49
|
-
# from the credentials page. The REFRESH_TOKEN must be obtained uncommenting
|
50
|
-
# some rows from the method below and obtaining an access_token via a browser
|
51
|
-
# logged in to your google account.
|
52
|
-
def log_into_google_drive_via_oauth2
|
53
|
-
credentials = Google::Auth::UserRefreshCredentials.new(
|
54
|
-
client_id: SpreadsheetGoodies.configuration.google_client_id,
|
55
|
-
client_secret: SpreadsheetGoodies.configuration.client_secret,
|
56
|
-
scope: [
|
57
|
-
'https://www.googleapis.com/auth/drive',
|
58
|
-
'https://spreadsheets.google.com/feeds/',
|
59
|
-
],
|
60
|
-
redirect_uri: 'urn:ietf:wg:oauth:2.0:oob'
|
61
|
-
)
|
62
|
-
credentials.refresh_token = SpreadsheetGoodies.configuration.refresh_token if SpreadsheetGoodies.configuration.refresh_token
|
63
|
-
|
64
|
-
# Uncomment the rows below to obtain the refresh_token:
|
65
|
-
# print("1. Open this page:\n%s\n\n" % credentials.authorization_uri)
|
66
|
-
# print("2. Enter the authorization code shown in the page: ")
|
67
|
-
# credentials.code = $stdin.gets.chomp
|
68
|
-
# credentials.fetch_access_token!
|
69
|
-
# puts credentials.refresh_token
|
70
|
-
# debugger
|
71
|
-
|
72
|
-
begin
|
73
|
-
credentials.fetch_access_token!
|
74
|
-
rescue Faraday::ConnectionFailed
|
75
|
-
logger.info 'Error logging into Google Drive. Is your internet connection down?'
|
76
|
-
exit
|
77
|
-
end
|
78
|
-
|
79
|
-
session = GoogleDrive::Session.from_credentials(credentials)
|
80
|
-
end
|
81
|
-
|
82
|
-
# Authenticate with Google Drive via a service account.
|
83
|
-
# Your service accounts can be accessed at https://console.developers.google.com/apis/credentials,
|
84
|
-
# logged with your Google account in your custom project.
|
85
|
-
# The service accounts are at 'IAM and administrator' > 'Service accounts'.
|
86
|
-
# The keys are at 'API manager' > 'Credentials'.
|
87
|
-
def log_into_google_drive_via_service_account
|
88
|
-
session = GoogleDrive::Session.from_service_account_key(
|
89
|
-
StringIO.new(SpreadsheetGoodies.configuration.service_account_key_json)
|
90
|
-
)
|
91
|
-
session
|
92
|
-
end
|
93
|
-
end
|
@@ -1,68 +0,0 @@
|
|
1
|
-
require_relative 'google_drive_worksheet_row'
|
2
|
-
require 'csv'
|
3
|
-
|
4
|
-
# A cached copy of a Google Spreadsheets worksheet (i.e., a single workbook "tab"),
|
5
|
-
# stored as an array of arrays. Individual cells can be accessed by column title.
|
6
|
-
# Example:
|
7
|
-
# worksheet[0]['A column title']
|
8
|
-
class SpreadsheetGoodies::GoogleDriveWorksheet
|
9
|
-
attr_reader :rows, :header_row
|
10
|
-
|
11
|
-
# @param worksheet_title_or_index [String] Sheet name; if unspecified, the
|
12
|
-
# first sheet will be used.
|
13
|
-
# @param num_header_rows [Integer] Number of rows at the top of the sheet that
|
14
|
-
# contain headers or stuff other than data. Optional; if unspecified, assumes
|
15
|
-
# that a single top row contains the header and all rows below are data.
|
16
|
-
def initialize(spreadsheet_key, worksheet_title=nil, num_header_rows=1)
|
17
|
-
@spreadsheet_key = spreadsheet_key
|
18
|
-
@worksheet_title = worksheet_title
|
19
|
-
@num_header_rows = num_header_rows
|
20
|
-
end
|
21
|
-
|
22
|
-
# Reads sheet contents and caches it into instance variables to so that it
|
23
|
-
# can be accessed later without accessing Google Drive.
|
24
|
-
def read_from_google_drive
|
25
|
-
worksheet_contents = read_worksheet.export_as_string.force_encoding('utf-8')
|
26
|
-
|
27
|
-
rows = CSV::parse(worksheet_contents)
|
28
|
-
|
29
|
-
if SpreadsheetGoodies.configuration.strip_values_on_read
|
30
|
-
rows = rows.map do |row|
|
31
|
-
row.map {|element| element.try(:strip) }
|
32
|
-
end
|
33
|
-
end
|
34
|
-
|
35
|
-
@header_row = rows[@num_header_rows-1]
|
36
|
-
@rows = rows.collect.with_index do |row, index|
|
37
|
-
GoogleDriveWorksheetRow.new(@header_row, index+1, *row)
|
38
|
-
end
|
39
|
-
|
40
|
-
self
|
41
|
-
end
|
42
|
-
|
43
|
-
def [](index)
|
44
|
-
@rows[index]
|
45
|
-
end
|
46
|
-
|
47
|
-
# Return only the rows that contain data (excludes the header rows)
|
48
|
-
def data_rows
|
49
|
-
@rows[@num_header_rows..-1]
|
50
|
-
end
|
51
|
-
|
52
|
-
# Finds and returns the first row that contains cell_value at the given column
|
53
|
-
def find_row_by_column_value(column_title, cell_value)
|
54
|
-
data_rows.each do |row|
|
55
|
-
return row if row[column_title] == cell_value
|
56
|
-
end
|
57
|
-
|
58
|
-
nil
|
59
|
-
end
|
60
|
-
|
61
|
-
# Reads a GoogleDrive::Spreadsheet object from Google Drive. The sheet object
|
62
|
-
# can be used to write data to the online spreadhseet, as we don't yet provide
|
63
|
-
# the helper methods for our users to do it via our public interface.
|
64
|
-
def read_worksheet
|
65
|
-
connector = SpreadsheetGoodies::GoogleDriveConnector.new
|
66
|
-
connector.read_worksheet(@spreadsheet_key, @worksheet_title)
|
67
|
-
end
|
68
|
-
end
|
@@ -1,23 +0,0 @@
|
|
1
|
-
class SpreadsheetGoodies::GoogleDriveWorksheet
|
2
|
-
|
3
|
-
# Sobrecarrega método [] da Array para permitir acessar células passando
|
4
|
-
# o título da coluna como índice. Ex: row['Data formal do pedido']
|
5
|
-
class ::GoogleDriveWorksheetRow < Array
|
6
|
-
attr_reader :header_row, :row_number
|
7
|
-
|
8
|
-
def initialize(header_row, sheet_row_number, *args)
|
9
|
-
@header_row = header_row
|
10
|
-
@row_number = sheet_row_number
|
11
|
-
super(args)
|
12
|
-
end
|
13
|
-
|
14
|
-
def [](locator)
|
15
|
-
if locator.is_a?(String)
|
16
|
-
return self[ @header_row.index(locator) ]
|
17
|
-
else
|
18
|
-
return super(locator)
|
19
|
-
end
|
20
|
-
end
|
21
|
-
end
|
22
|
-
|
23
|
-
end
|