workbook 0.8.1 → 0.9.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.codeclimate.yml +21 -0
- data/.gitignore +4 -1
- data/.ruby-version +1 -1
- data/.travis.yml +4 -4
- data/CHANGELOG.md +8 -0
- data/Gemfile +2 -2
- data/README.md +9 -7
- data/Rakefile +6 -6
- data/json_test.json +1 -0
- data/lib/workbook/book.rb +73 -62
- data/lib/workbook/cell.rb +58 -13
- data/lib/workbook/column.rb +31 -28
- data/lib/workbook/format.rb +23 -24
- data/lib/workbook/generatetypes.rb +4 -4
- data/lib/workbook/modules/cache.rb +6 -7
- data/lib/workbook/modules/cell.rb +77 -100
- data/lib/workbook/modules/diff_sort.rb +92 -83
- data/lib/workbook/modules/raw_objects_storage.rb +6 -8
- data/lib/workbook/modules/type_parser.rb +30 -22
- data/lib/workbook/nil_value.rb +4 -9
- data/lib/workbook/readers/csv_reader.rb +7 -10
- data/lib/workbook/readers/ods_reader.rb +51 -50
- data/lib/workbook/readers/txt_reader.rb +6 -8
- data/lib/workbook/readers/xls_reader.rb +21 -33
- data/lib/workbook/readers/xls_shared.rb +106 -117
- data/lib/workbook/readers/xlsx_reader.rb +45 -46
- data/lib/workbook/row.rb +99 -84
- data/lib/workbook/sheet.rb +47 -38
- data/lib/workbook/table.rb +96 -72
- data/lib/workbook/template.rb +12 -15
- data/lib/workbook/types/false.rb +0 -1
- data/lib/workbook/types/nil.rb +0 -1
- data/lib/workbook/types/nil_class.rb +1 -1
- data/lib/workbook/types/numeric.rb +1 -1
- data/lib/workbook/types/string.rb +1 -1
- data/lib/workbook/types/time.rb +1 -1
- data/lib/workbook/types/true.rb +0 -1
- data/lib/workbook/types/true_class.rb +1 -1
- data/lib/workbook/version.rb +2 -3
- data/lib/workbook/writers/csv_table_writer.rb +10 -13
- data/lib/workbook/writers/html_writer.rb +34 -38
- data/lib/workbook/writers/json_table_writer.rb +8 -11
- data/lib/workbook/writers/xls_writer.rb +30 -36
- data/lib/workbook/writers/xlsx_writer.rb +45 -29
- data/lib/workbook.rb +16 -15
- data/test/artifacts/currency_test.ods +0 -0
- data/test/helper.rb +6 -5
- data/test/test_book.rb +41 -38
- data/test/test_column.rb +26 -24
- data/test/test_format.rb +51 -55
- data/test/test_functional.rb +7 -8
- data/test/test_modules_cache.rb +18 -17
- data/test/test_modules_cell.rb +55 -46
- data/test/test_modules_table_diff_sort.rb +55 -64
- data/test/test_modules_type_parser.rb +61 -31
- data/test/test_readers_csv_reader.rb +48 -42
- data/test/test_readers_ods_reader.rb +36 -31
- data/test/test_readers_txt_reader.rb +21 -23
- data/test/test_readers_xls_reader.rb +20 -23
- data/test/test_readers_xls_shared.rb +2 -3
- data/test/test_readers_xlsx_reader.rb +44 -37
- data/test/test_row.rb +105 -109
- data/test/test_sheet.rb +35 -41
- data/test/test_table.rb +82 -60
- data/test/test_template.rb +16 -15
- data/test/test_types_date.rb +4 -6
- data/test/test_writers_csv_writer.rb +24 -0
- data/test/test_writers_html_writer.rb +42 -41
- data/test/test_writers_json_writer.rb +16 -9
- data/test/test_writers_xls_writer.rb +50 -35
- data/test/test_writers_xlsx_writer.rb +62 -34
- data/workbook.gemspec +25 -27
- metadata +96 -42
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 898a4a79301299545d91cfdd5b5f1f261f4cde32337d4713256f21d894cc49f0
|
4
|
+
data.tar.gz: ee61cd9e3e3687092b5c8ca82e8aa10bf8f846553a3602ce3c46103b43ee4e9b
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 27b2ab505f2ff035a12e839db5148337c504d81bb2c2517b2eb1ac4749df5e47f31fd281386c4c4d4880c2e24c75a3630d02c7a7bb13e5f62789543bf991f7f9
|
7
|
+
data.tar.gz: 465f709b61f96afe734739b214d1b56daa06e837ea8cd85f98c9343f9c1f7d3337409616bdc5617fa456de3718427d0d89ae89c1fa40a13efe4afbe8841ac175
|
data/.codeclimate.yml
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
version: "2"
|
2
|
+
plugins:
|
3
|
+
rubocop:
|
4
|
+
enabled: true
|
5
|
+
channel: rubocop-1-23-0
|
6
|
+
brakeman:
|
7
|
+
enabled: false
|
8
|
+
exclude_patterns:
|
9
|
+
- "config/"
|
10
|
+
- "db/"
|
11
|
+
- "dist/"
|
12
|
+
- "features/"
|
13
|
+
- "**/node_modules/"
|
14
|
+
- "script/"
|
15
|
+
- "**/spec/"
|
16
|
+
- "**/test/"
|
17
|
+
- "**/tests/"
|
18
|
+
- "Tests/"
|
19
|
+
- "**/vendor/"
|
20
|
+
- "**/*_test.go"
|
21
|
+
- "**/*.d.ts"
|
data/.gitignore
CHANGED
data/.ruby-version
CHANGED
@@ -1 +1 @@
|
|
1
|
-
2.
|
1
|
+
3.2.1
|
data/.travis.yml
CHANGED
data/CHANGELOG.md
CHANGED
@@ -1,5 +1,13 @@
|
|
1
1
|
# Changelog
|
2
2
|
|
3
|
+
### 0.9.0
|
4
|
+
|
5
|
+
* Dropped inheritance from Array and borrowed from the Enumerable module instead (this might break some existing implementations; please create pull request if you miss Array like functionality)
|
6
|
+
* Fix: ODS: Currency formatted cell now no longer returns String
|
7
|
+
|
8
|
+
### 0.8.1
|
9
|
+
|
10
|
+
* Adopted [Standard](https://github.com/testdouble/standard) for code formatting
|
3
11
|
|
4
12
|
### 0.8.0
|
5
13
|
|
data/Gemfile
CHANGED
data/README.md
CHANGED
@@ -1,7 +1,10 @@
|
|
1
1
|
# Workbook
|
2
|
-
[![Code Climate](https://codeclimate.com/github/murb/workbook.
|
2
|
+
[![Code Climate](https://codeclimate.com/github/murb/workbook.svg)](https://codeclimate.com/github/murb/workbook)
|
3
|
+
[![Test Coverage](https://api.codeclimate.com/v1/badges/058655e705a3f36896e0/test_coverage)](https://codeclimate.com/github/murb/workbook/test_coverage)
|
4
|
+
[![Build Status](https://travis-ci.org/murb/workbook.svg?branch=master)](https://travis-ci.org/murb/workbook)
|
5
|
+
[![Gem Version](https://badge.fury.io/rb/workbook.svg)](http://badge.fury.io/rb/workbook)
|
3
6
|
|
4
|
-
Goal of this gem is to make working with workbooks (spreadsheets) as programmer friendly as possible. Not reinventing a totally new DSL or all kinds of new methodnames, but just borrowing from known concepts such as hashes and arrays (much like (Faster)CSV does)). Workbook is a gem that mimicks a typical spreadsheet, a bundle of sheets, bundled in a *workbook*. A sheet may contain one or more tables (which might the multi table sheets of Apple Numbers or Excel ranges). Basically:
|
7
|
+
Goal of this gem is to make working with workbooks (spreadsheets) as programmer friendly as possible. Not reinventing a totally new DSL or all kinds of new methodnames, but just borrowing from known concepts such as hashes and arrays (much like (Faster)CSV does)). Workbook is a gem that mimicks a typical spreadsheet, a bundle of sheets, bundled in a *workbook*. A sheet may contain one or more tables (which might be the multi table sheets of Apple Numbers or Excel ranges). Basically:
|
5
8
|
|
6
9
|
* Book
|
7
10
|
* Sheet (one or more)
|
@@ -13,7 +16,7 @@ Subsequently a table consists of:
|
|
13
16
|
* Row (one or more)
|
14
17
|
* Cell ( wich has may have a (shared) Format )
|
15
18
|
|
16
|
-
Book, Sheet, Table and Row inherit from the
|
19
|
+
Book, Sheet, Table and Row inherit much of the behaviours from the Array and Hash classes, it tries to walk and quack as such. The row is extended with hashlike lookups (`row[:id]`) and writers (`row[:id]=`). Values are converted to ruby native types, and optional parsers can be added to improve recognition.
|
17
20
|
|
18
21
|
In addition to offering you this plain structure it allows for importing .xls, .csv, .xlsx, .txt files (more to come), writing .xls, and .csv (more to come) and includes several utilities to easily create an overview of the differences between two tables and output basic cell-styling properties as css.
|
19
22
|
|
@@ -32,7 +35,7 @@ Calling
|
|
32
35
|
s = b.sheet
|
33
36
|
t = s.table
|
34
37
|
|
35
|
-
will give you
|
38
|
+
will give you the first Sheet and Table (if one doesn't exist it is created on the fly).
|
36
39
|
|
37
40
|
You can initialize with simple 2-d array like this:
|
38
41
|
|
@@ -129,8 +132,7 @@ In case you want to display a formatted table in HTML, some conversion is offere
|
|
129
132
|
|
130
133
|
## Compatibility
|
131
134
|
|
132
|
-
Workbook is automatically tested
|
133
|
-
Check [Travis for Workbook's current build status](https://travis-ci.org/murb/workbook) [![Build Status](https://travis-ci.org/murb/workbook.svg?branch=master)](https://travis-ci.org/murb/workbook).
|
135
|
+
Workbook is automatically tested. Check [Travis for Workbook's current build status of the supported ruby versions](https://travis-ci.org/murb/workbook) [![Build Status](https://travis-ci.org/murb/workbook.svg?branch=master)](https://travis-ci.org/murb/workbook).
|
134
136
|
|
135
137
|
## Future
|
136
138
|
|
@@ -153,4 +155,4 @@ Workbook uses the following gems:
|
|
153
155
|
* [FasterCSV](http://fastercsv.rubyforge.org/) Used for reading CSV (comma separated text) and TXT (tab separated text) files (Copyright © James Edward Gray II; GPL2 & Ruby License)
|
154
156
|
* [rchardet](http://rubyforge.org/projects/rchardet) Used for detecting encoding in CSV and TXT importers (Copyright © JMHodges; LGPL)
|
155
157
|
* [axslx](https://github.com/randym/axlsx) Used for writing the newer .xlsx files (with formatting) (Copyright © 2011, 2012 Randy Morgan, MIT License)
|
156
|
-
* [Nokogiri](http://nokogiri.org/) Used for reading ODS documents (Copyright © 2008 - 2012 Aaron Patterson, Mike Dalessio, Charles Nutter, Sergio Arbeo, Patrick Mahoney, Yoko Harada; MIT Licensed)
|
158
|
+
* [Nokogiri](http://nokogiri.org/) Used for reading ODS documents (Copyright © 2008 - 2012 Aaron Patterson, Mike Dalessio, Charles Nutter, Sergio Arbeo, Patrick Mahoney, Yoko Harada; MIT Licensed)
|
data/Rakefile
CHANGED
@@ -1,16 +1,16 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require
|
4
|
-
require
|
5
|
-
require
|
3
|
+
require "rake"
|
4
|
+
require "rake/testtask"
|
5
|
+
require "bundler"
|
6
6
|
require "bundler/gem_tasks"
|
7
7
|
|
8
|
-
#Bundler::GemHelper.install_tasks
|
8
|
+
# Bundler::GemHelper.install_tasks
|
9
9
|
|
10
|
-
task :
|
10
|
+
task default: [:test]
|
11
11
|
|
12
12
|
Rake::TestTask.new do |t|
|
13
13
|
t.libs << "test"
|
14
|
-
t.test_files = FileList[
|
14
|
+
t.test_files = FileList["test/test*.rb", "test/writers/test*.rb"]
|
15
15
|
t.verbose = false
|
16
16
|
end
|
data/json_test.json
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
[{"a":1,"b":2},{"a":"2012-01-01","b":null}]
|
data/lib/workbook/book.rb
CHANGED
@@ -1,19 +1,18 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
|
-
|
3
|
-
# -*- encoding : utf-8 -*-
|
4
2
|
# frozen_string_literal: true
|
5
|
-
|
6
|
-
require
|
7
|
-
require
|
8
|
-
require
|
9
|
-
require
|
10
|
-
require
|
11
|
-
require
|
12
|
-
require
|
13
|
-
require
|
14
|
-
require
|
15
|
-
require
|
16
|
-
require
|
3
|
+
|
4
|
+
require "forwardable"
|
5
|
+
require "open-uri"
|
6
|
+
require "workbook/writers/xls_writer"
|
7
|
+
require "workbook/writers/xlsx_writer"
|
8
|
+
require "workbook/writers/html_writer"
|
9
|
+
require "workbook/readers/xls_reader"
|
10
|
+
require "workbook/readers/xls_shared"
|
11
|
+
require "workbook/readers/xlsx_reader"
|
12
|
+
require "workbook/readers/ods_reader"
|
13
|
+
require "workbook/readers/csv_reader"
|
14
|
+
require "workbook/readers/txt_reader"
|
15
|
+
require "workbook/modules/diff_sort"
|
17
16
|
|
18
17
|
module Workbook
|
19
18
|
# The Book class is the container of sheets. It can be inialized by either the standard initalizer or the open method. The
|
@@ -35,8 +34,9 @@ module Workbook
|
|
35
34
|
"CDF V2 Document, No summary info"
|
36
35
|
]
|
37
36
|
|
38
|
-
class Book
|
39
|
-
|
37
|
+
class Book
|
38
|
+
include Enumerable
|
39
|
+
extend Forwardable
|
40
40
|
|
41
41
|
include Workbook::Readers::XlsShared
|
42
42
|
include Workbook::Writers::XlsWriter
|
@@ -49,14 +49,13 @@ module Workbook
|
|
49
49
|
include Workbook::Readers::TxtReader
|
50
50
|
include Workbook::Modules::BookDiffSort
|
51
51
|
|
52
|
+
delegate [:last, :pop, :delete_at, :each, :[]] => :@sheets
|
53
|
+
|
52
54
|
# @param [Workbook::Sheet, Array] sheet create a new workbook based on an existing sheet, or initialize a sheet based on the array
|
53
55
|
# @return [Workbook::Book]
|
54
|
-
def initialize sheet=nil
|
55
|
-
|
56
|
-
|
57
|
-
elsif sheet
|
58
|
-
self.push Workbook::Sheet.new(sheet, self, {})
|
59
|
-
end
|
56
|
+
def initialize sheet = nil
|
57
|
+
@sheets = []
|
58
|
+
push sheet if sheet
|
60
59
|
end
|
61
60
|
|
62
61
|
# @return [Workbook::Template] returns the template describing how the document should be/is formatted
|
@@ -74,37 +73,51 @@ module Workbook
|
|
74
73
|
#
|
75
74
|
# @return [String] the title of the workbook
|
76
75
|
def title
|
77
|
-
|
76
|
+
defined?(@title) && !@title.nil? ? @title : "untitled document"
|
78
77
|
end
|
79
78
|
|
80
|
-
|
81
|
-
@title = t
|
82
|
-
end
|
79
|
+
attr_writer :title
|
83
80
|
|
84
81
|
# Push (like in array) a sheet to the workbook (parameter is optional, default is a new sheet)
|
85
82
|
#
|
86
|
-
# @param [Workbook::Sheet] sheet
|
87
|
-
def push sheet=Workbook::Sheet.new
|
88
|
-
|
89
|
-
sheet.book=
|
83
|
+
# @param [Workbook::Sheet, Array[Array]] sheet
|
84
|
+
def push sheet = Workbook::Sheet.new
|
85
|
+
sheet = Workbook::Sheet.new(sheet) unless sheet.is_a? Workbook::Sheet
|
86
|
+
sheet.book = self
|
87
|
+
|
88
|
+
@sheets.push(sheet)
|
89
|
+
sheet
|
90
90
|
end
|
91
91
|
|
92
|
-
#
|
92
|
+
# Inserts a new Table at the specified index
|
93
93
|
#
|
94
|
-
# @param [
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
94
|
+
# @param [Integer] index of the table
|
95
|
+
# @param [Workbook::Table, Array<Array>] table The new first table of this sheet
|
96
|
+
#
|
97
|
+
# @return [Workbook::Table]
|
98
|
+
def []= index, value
|
99
|
+
table_to_insert = value.is_a?(Workbook::Sheet) ? value : Workbook::Sheet.new
|
100
|
+
table_to_insert.book = self
|
101
|
+
@sheets[index] = table_to_insert
|
99
102
|
end
|
100
103
|
|
104
|
+
# returns the index of an item
|
105
|
+
def index item
|
106
|
+
@sheets.index item
|
107
|
+
end
|
108
|
+
|
109
|
+
# << (like in array) a sheet to the workbook (parameter is optional, default is a new sheet)
|
110
|
+
#
|
111
|
+
# @param [Workbook::Sheet, Array[Array]] sheet
|
112
|
+
def << sheet = Workbook::Sheet.new
|
113
|
+
push sheet
|
114
|
+
end
|
101
115
|
|
102
116
|
# Sheet returns the first sheet of a workbook, or an empty one.
|
103
117
|
#
|
104
118
|
# @return [Workbook::Sheet] The first sheet, and creates an empty one if one doesn't exists
|
105
119
|
def sheet
|
106
|
-
|
107
|
-
first
|
120
|
+
first || push
|
108
121
|
end
|
109
122
|
|
110
123
|
# If the first sheet has any contents
|
@@ -119,9 +132,9 @@ module Workbook
|
|
119
132
|
# @param [String] filename a string with a reference to the file to be opened
|
120
133
|
# @param [String] extension an optional string enforcing a certain parser (based on the file extension, e.g. 'txt', 'csv' or 'xls')
|
121
134
|
# @return [Workbook::Book] A new instance, based on the filename
|
122
|
-
def import filename, extension=nil, options={}
|
123
|
-
extension
|
124
|
-
if [
|
135
|
+
def import filename, extension = nil, options = {}
|
136
|
+
extension ||= file_extension(filename)
|
137
|
+
if ["txt", "csv", "xml"].include?(extension)
|
125
138
|
open_text filename, extension, options
|
126
139
|
else
|
127
140
|
open_binary filename, extension, options
|
@@ -133,9 +146,9 @@ module Workbook
|
|
133
146
|
# @param [String] filename a string with a reference to the file to be opened
|
134
147
|
# @param [String] extension an optional string enforcing a certain parser (based on the file extension, e.g. 'txt', 'csv' or 'xls')
|
135
148
|
# @return [Workbook::Book] A new instance, based on the filename
|
136
|
-
def open_binary filename, extension=nil, options={}
|
137
|
-
extension
|
138
|
-
f = open(filename)
|
149
|
+
def open_binary filename, extension = nil, options = {}
|
150
|
+
extension ||= file_extension(filename)
|
151
|
+
f = File.open(filename)
|
139
152
|
send("load_#{extension}".to_sym, f, options)
|
140
153
|
end
|
141
154
|
|
@@ -143,9 +156,9 @@ module Workbook
|
|
143
156
|
#
|
144
157
|
# @param [String] filename a string with a reference to the file to be opened
|
145
158
|
# @param [String] extension an optional string enforcing a certain parser (based on the file extension, e.g. 'txt', 'csv' or 'xls')
|
146
|
-
def open_text filename, extension=nil, options={}
|
147
|
-
extension
|
148
|
-
t = text_to_utf8(open(filename).read)
|
159
|
+
def open_text filename, extension = nil, options = {}
|
160
|
+
extension ||= file_extension(filename)
|
161
|
+
t = text_to_utf8(File.open(filename).read)
|
149
162
|
send("load_#{extension}".to_sym, t, options)
|
150
163
|
end
|
151
164
|
|
@@ -153,21 +166,20 @@ module Workbook
|
|
153
166
|
#
|
154
167
|
# @param [String] filename a string with a reference to the file to be written to
|
155
168
|
# @param [Hash] options depends on the writer chosen by the file's filetype
|
156
|
-
def write filename, options={}
|
169
|
+
def write filename, options = {}
|
157
170
|
extension = file_extension(filename)
|
158
171
|
send("write_to_#{extension}".to_sym, filename, options)
|
159
172
|
end
|
160
173
|
|
161
|
-
|
162
174
|
# Helper method to convert text in a file to UTF-8
|
163
175
|
#
|
164
176
|
# @param [String] text a string to convert
|
165
177
|
def text_to_utf8 text
|
166
|
-
unless text.valid_encoding?
|
178
|
+
unless text.valid_encoding? && (text.encoding == "UTF-8")
|
167
179
|
# TODO: had some ruby 1.9 problems with rchardet ... but ideally it or a similar functionality will be reintroduced
|
168
180
|
source_encoding = text.valid_encoding? ? text.encoding : "US-ASCII"
|
169
|
-
text = text.encode(
|
170
|
-
text = text.
|
181
|
+
text = text.encode("UTF-8", source_encoding, invalid: :replace, undef: :replace, replace: "")
|
182
|
+
text = text.delete("\u0000") # TODO: this cleanup of nil values isn't supposed to be needed...
|
171
183
|
end
|
172
184
|
text
|
173
185
|
end
|
@@ -176,16 +188,16 @@ module Workbook
|
|
176
188
|
#
|
177
189
|
# @return [String] The file extension
|
178
190
|
def file_extension(filename)
|
179
|
-
ext = File.extname(filename).
|
191
|
+
ext = File.extname(filename).delete(".").downcase if filename
|
180
192
|
# for remote files which has asset id after extension
|
181
|
-
ext.split(
|
193
|
+
ext.split("?")[0]
|
182
194
|
end
|
183
195
|
|
184
196
|
# Load the CSV data contained in the given StringIO or String object
|
185
197
|
#
|
186
198
|
# @param [StringIO] stringio_or_string StringIO stream or String object, with data in CSV format
|
187
199
|
# @param [Symbol] filetype (currently only :csv or :txt), indicating the format of the first parameter
|
188
|
-
def read(stringio_or_string, filetype, options={})
|
200
|
+
def read(stringio_or_string, filetype, options = {})
|
189
201
|
raise ArgumentError.new("The filetype parameter should be either :csv or :txt") unless [:csv, :txt].include?(filetype)
|
190
202
|
t = stringio_or_string.respond_to?(:read) ? stringio_or_string.read : stringio_or_string.to_s
|
191
203
|
t = text_to_utf8(t)
|
@@ -197,7 +209,7 @@ module Workbook
|
|
197
209
|
# @param [Integer] index the index of the sheet
|
198
210
|
def create_or_open_sheet_at index
|
199
211
|
s = self[index]
|
200
|
-
s = self[index] = Workbook::Sheet.new if s
|
212
|
+
s = self[index] = Workbook::Sheet.new if s.nil?
|
201
213
|
s.book = self
|
202
214
|
s
|
203
215
|
end
|
@@ -208,10 +220,10 @@ module Workbook
|
|
208
220
|
# @param [String] filename of the document
|
209
221
|
# @param [String] extension of the document (not required). The parser used is based on the extension of the file, this option allows you to override the default.
|
210
222
|
# @return [Workbook::Book] A new instance, based on the filename
|
211
|
-
def open filename, extension=nil
|
212
|
-
wb =
|
223
|
+
def open filename, extension = nil
|
224
|
+
wb = new
|
213
225
|
wb.import filename, extension
|
214
|
-
|
226
|
+
wb
|
215
227
|
end
|
216
228
|
|
217
229
|
# Create an instance from the given stream or string, which should be in CSV or TXT format
|
@@ -219,12 +231,11 @@ module Workbook
|
|
219
231
|
# @param [StringIO] stringio_or_string StringIO stream or String object, with data in CSV or TXT format
|
220
232
|
# @param [Symbol] filetype (currently only :csv or :txt), indicating the format of the first parameter
|
221
233
|
# @return [Workbook::Book] A new instance
|
222
|
-
def read stringio_or_string, filetype, options={}
|
223
|
-
wb =
|
234
|
+
def read stringio_or_string, filetype, options = {}
|
235
|
+
wb = new
|
224
236
|
wb.read(stringio_or_string, filetype, options)
|
225
237
|
wb
|
226
238
|
end
|
227
|
-
|
228
239
|
end
|
229
240
|
end
|
230
241
|
end
|
data/lib/workbook/cell.rb
CHANGED
@@ -1,20 +1,65 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
|
-
|
3
|
-
# -*- encoding : utf-8 -*-
|
4
2
|
# frozen_string_literal: true
|
5
|
-
|
3
|
+
|
4
|
+
require "workbook/modules/cell"
|
6
5
|
|
7
6
|
module Workbook
|
8
7
|
class Cell
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
8
|
+
include Workbook::Modules::Cell
|
9
|
+
|
10
|
+
class << self
|
11
|
+
|
12
|
+
# returns a symbol representation of a string.
|
13
|
+
# @param [String] value to convert
|
14
|
+
# @example
|
15
|
+
#
|
16
|
+
# <Workbook::Cell value="yet another value">.to_sym # returns :yet_another_value
|
17
|
+
def value_to_sym value
|
18
|
+
v = nil
|
19
|
+
cell_type ||= ::Workbook::Modules::Cell::CLASS_CELLTYPE_MAPPING[value.class.to_s]
|
20
|
+
value_to_s = value.to_s.strip.downcase
|
21
|
+
unless value.nil? || value_to_s == ""
|
22
|
+
if cell_type == :integer
|
23
|
+
v = "num#{value}".to_sym
|
24
|
+
elsif cell_type == :float
|
25
|
+
v = "num#{value}".sub(".", "_").to_sym
|
26
|
+
else
|
27
|
+
v = value_to_s.strip
|
28
|
+
ends_with_exclamationmark = (v[-1] == "!")
|
29
|
+
ends_with_questionmark = (v[-1] == "?")
|
30
|
+
|
31
|
+
v = _replace_possibly_problematic_characters_from_string(v)
|
32
|
+
|
33
|
+
v = v.encode(Encoding.find("ASCII"), invalid: :replace, undef: :replace, replace: "")
|
34
|
+
|
35
|
+
v = "#{v}!" if ends_with_exclamationmark
|
36
|
+
v = "#{v}?" if ends_with_questionmark
|
37
|
+
v = v.downcase.to_sym
|
38
|
+
end
|
39
|
+
end
|
40
|
+
v
|
41
|
+
end
|
42
|
+
|
43
|
+
private
|
44
|
+
|
45
|
+
def _replace_possibly_problematic_characters_from_string(string)
|
46
|
+
Workbook::Modules::Cell::CHARACTER_REPACEMENTS.each do |ac, rep|
|
47
|
+
ac.each do |s|
|
48
|
+
string = string.gsub(s, rep)
|
49
|
+
end
|
50
|
+
end
|
51
|
+
string
|
52
|
+
end
|
53
|
+
|
54
|
+
end
|
55
|
+
|
56
|
+
# @param [Numeric,String,Time,Date,TrueClass,FalseClass,NilClass] value a valid value
|
57
|
+
# @param [Hash] options a reference to :format (Workbook::Format) can be specified
|
58
|
+
def initialize value = nil, options = {}
|
59
|
+
self.format = options[:format] if options[:format]
|
60
|
+
self.row = options[:row]
|
61
|
+
self.value = value
|
62
|
+
@to_sym = nil
|
63
|
+
end
|
19
64
|
end
|
20
65
|
end
|
data/lib/workbook/column.rb
CHANGED
@@ -1,35 +1,39 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
|
-
|
3
|
-
# -*- encoding : utf-8 -*-
|
4
2
|
# frozen_string_literal: true
|
3
|
+
|
5
4
|
module Workbook
|
5
|
+
# Column helps us to store general properties of a column, and lets us easily perform operations on values within a column, it also exposes a read only Enumerable API to access the cells in the column.
|
6
6
|
|
7
|
-
# Column helps us to store general properties of a column, and lets us easily perform operations on values within a column
|
8
7
|
class Column
|
9
|
-
|
8
|
+
include Enumerable
|
9
|
+
extend Forwardable
|
10
|
+
|
11
|
+
delegate [:first, :last, :each, :count, :include?, :index, :to_csv, :length, :empty?] => :cells
|
10
12
|
|
11
|
-
|
13
|
+
attr_accessor :limit, :width # character limit
|
14
|
+
|
15
|
+
def initialize(table = nil, options = {})
|
12
16
|
self.table = table
|
13
|
-
options.each{ |k,v|
|
17
|
+
options.each { |k, v| public_send("#{k}=", v) }
|
14
18
|
end
|
15
19
|
|
16
20
|
# Returns column type, either :primary_key, :string, :text, :integer, :float, :decimal, :datetime, :date, :binary, :boolean
|
17
21
|
def column_type
|
18
22
|
return @column_type if defined?(@column_type)
|
19
|
-
ind =
|
23
|
+
ind = index
|
20
24
|
table[1..500].each do |row|
|
21
|
-
if row[ind]
|
25
|
+
if row[ind]&.cell_type
|
22
26
|
cel_column_type = row[ind].cell_type
|
23
|
-
if !defined?(@column_type)
|
27
|
+
if !defined?(@column_type) || @column_type.nil?
|
24
28
|
@column_type = cel_column_type
|
25
|
-
elsif cel_column_type == @column_type
|
29
|
+
elsif (cel_column_type == @column_type) || (cel_column_type == :nil)
|
26
30
|
else
|
27
31
|
@column_type = :string
|
28
32
|
break
|
29
33
|
end
|
30
34
|
end
|
31
35
|
end
|
32
|
-
|
36
|
+
@column_type
|
33
37
|
end
|
34
38
|
|
35
39
|
# Returns index of the column within the table's columns-set
|
@@ -41,14 +45,12 @@ module Workbook
|
|
41
45
|
# Set the table this column belongs to
|
42
46
|
# @param [Workbook::Table] table this column belongs to
|
43
47
|
def table= table
|
44
|
-
raise(ArgumentError, "value should be nil or Workbook::Table") unless [NilClass,Workbook::Table].include? table.class
|
48
|
+
raise(ArgumentError, "value should be nil or Workbook::Table") unless [NilClass, Workbook::Table].include? table.class
|
45
49
|
@table = table
|
46
50
|
end
|
47
51
|
|
48
52
|
# @return [Workbook::Table]
|
49
|
-
|
50
|
-
@table
|
51
|
-
end
|
53
|
+
attr_reader :table
|
52
54
|
|
53
55
|
def column_type= column_type
|
54
56
|
if [:primary_key, :string, :text, :integer, :float, :decimal, :datetime, :date, :binary, :boolean].include? column_type
|
@@ -59,25 +61,26 @@ module Workbook
|
|
59
61
|
end
|
60
62
|
end
|
61
63
|
|
64
|
+
def cells
|
65
|
+
table_header_object_id = table.header.object_id
|
66
|
+
table.map{|r| r[index] unless r.object_id == table_header_object_id }.compact
|
67
|
+
end
|
68
|
+
|
62
69
|
def head_value
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
return "!noheader!"
|
67
|
-
end
|
70
|
+
table.header[index].value
|
71
|
+
rescue
|
72
|
+
"!noheader!"
|
68
73
|
end
|
69
74
|
|
70
75
|
def inspect
|
71
76
|
"<Workbook::Column index=#{index}, header=#{head_value}>"
|
72
77
|
end
|
73
78
|
|
74
|
-
#default cell
|
75
|
-
|
76
|
-
return @default
|
77
|
-
end
|
79
|
+
# default cell
|
80
|
+
attr_reader :default
|
78
81
|
|
79
82
|
def default= value
|
80
|
-
@default = value if value.
|
83
|
+
@default = value if value.instance_of?(Cell)
|
81
84
|
@default = Cell.new(value)
|
82
85
|
end
|
83
86
|
|
@@ -87,10 +90,10 @@ module Workbook
|
|
87
90
|
# @return [Integer]
|
88
91
|
def alpha_index_to_number_index string
|
89
92
|
sum = 0
|
90
|
-
string.upcase.chars.each_with_index do |
|
91
|
-
sum = sum * 26 + char.
|
93
|
+
string.upcase.chars.each_with_index do |char, char_index|
|
94
|
+
sum = sum * 26 + char.unpack1("U") - 64
|
92
95
|
end
|
93
|
-
|
96
|
+
sum - 1
|
94
97
|
end
|
95
98
|
end
|
96
99
|
end
|