workbook 0.8.0 → 0.8.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (74) hide show
  1. checksums.yaml +4 -4
  2. data/.codeclimate.yml +21 -0
  3. data/.gitignore +4 -1
  4. data/.ruby-version +1 -1
  5. data/.travis.yml +4 -4
  6. data/CHANGELOG.md +16 -0
  7. data/Gemfile +4 -2
  8. data/README.md +9 -7
  9. data/Rakefile +9 -7
  10. data/lib/workbook/book.rb +74 -61
  11. data/lib/workbook/cell.rb +59 -12
  12. data/lib/workbook/column.rb +33 -29
  13. data/lib/workbook/format.rb +24 -23
  14. data/lib/workbook/generatetypes.rb +6 -5
  15. data/lib/workbook/modules/cache.rb +8 -7
  16. data/lib/workbook/modules/cell.rb +78 -99
  17. data/lib/workbook/modules/diff_sort.rb +93 -82
  18. data/lib/workbook/modules/raw_objects_storage.rb +7 -7
  19. data/lib/workbook/modules/type_parser.rb +31 -21
  20. data/lib/workbook/nil_value.rb +5 -9
  21. data/lib/workbook/readers/csv_reader.rb +7 -9
  22. data/lib/workbook/readers/ods_reader.rb +49 -49
  23. data/lib/workbook/readers/txt_reader.rb +7 -7
  24. data/lib/workbook/readers/xls_reader.rb +22 -32
  25. data/lib/workbook/readers/xls_shared.rb +107 -116
  26. data/lib/workbook/readers/xlsx_reader.rb +47 -46
  27. data/lib/workbook/row.rb +100 -83
  28. data/lib/workbook/sheet.rb +48 -37
  29. data/lib/workbook/table.rb +97 -71
  30. data/lib/workbook/template.rb +13 -14
  31. data/lib/workbook/types/date.rb +2 -1
  32. data/lib/workbook/types/false.rb +1 -1
  33. data/lib/workbook/types/false_class.rb +2 -1
  34. data/lib/workbook/types/nil.rb +1 -1
  35. data/lib/workbook/types/nil_class.rb +3 -2
  36. data/lib/workbook/types/numeric.rb +3 -2
  37. data/lib/workbook/types/string.rb +3 -2
  38. data/lib/workbook/types/time.rb +3 -2
  39. data/lib/workbook/types/true.rb +1 -1
  40. data/lib/workbook/types/true_class.rb +3 -2
  41. data/lib/workbook/version.rb +3 -2
  42. data/lib/workbook/writers/csv_table_writer.rb +11 -12
  43. data/lib/workbook/writers/html_writer.rb +35 -37
  44. data/lib/workbook/writers/json_table_writer.rb +9 -10
  45. data/lib/workbook/writers/xls_writer.rb +31 -35
  46. data/lib/workbook/writers/xlsx_writer.rb +46 -28
  47. data/lib/workbook.rb +17 -14
  48. data/test/helper.rb +8 -5
  49. data/test/test_book.rb +43 -38
  50. data/test/test_column.rb +29 -25
  51. data/test/test_format.rb +53 -55
  52. data/test/test_functional.rb +9 -8
  53. data/test/test_modules_cache.rb +20 -17
  54. data/test/test_modules_cell.rb +49 -46
  55. data/test/test_modules_table_diff_sort.rb +56 -63
  56. data/test/test_modules_type_parser.rb +63 -31
  57. data/test/test_readers_csv_reader.rb +50 -42
  58. data/test/test_readers_ods_reader.rb +30 -31
  59. data/test/test_readers_txt_reader.rb +23 -23
  60. data/test/test_readers_xls_reader.rb +22 -23
  61. data/test/test_readers_xls_shared.rb +5 -4
  62. data/test/test_readers_xlsx_reader.rb +46 -37
  63. data/test/test_row.rb +107 -109
  64. data/test/test_sheet.rb +43 -35
  65. data/test/test_table.rb +84 -60
  66. data/test/test_template.rb +18 -15
  67. data/test/test_types_date.rb +7 -7
  68. data/test/test_writers_csv_writer.rb +24 -0
  69. data/test/test_writers_html_writer.rb +44 -41
  70. data/test/test_writers_json_writer.rb +11 -9
  71. data/test/test_writers_xls_writer.rb +52 -35
  72. data/test/test_writers_xlsx_writer.rb +64 -34
  73. data/workbook.gemspec +26 -27
  74. metadata +93 -27
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 2d11f35120106855bbb5905a7f2611b138293157e135f86b0d8f5248c90f5f83
4
- data.tar.gz: ced9b91f1f1f69bbe90151ef78f61885a1ced541c5d3392e46dcb4e7770b58da
3
+ metadata.gz: 19f7a4905a129fba73781bb8ef9f672573419b5b754508bc3cc28aff968d5fb8
4
+ data.tar.gz: 7bd07336aaee461b7ff487c683b427ba29d717bee23731d80c1e74d1a1f7cd1e
5
5
  SHA512:
6
- metadata.gz: 1abccd53682ea4a4718153f0409e43925108740004dfbbba78419d4f80dd7a23add4677c7430812253a6e5559322b1919fb0f2c8f4450575804c8aae68056db6
7
- data.tar.gz: 6eb31d092e13c909e6d96d78a594bd3c1e9abd01d88a8cb76fc133c128035786d7f06651123e4c2f0798fa7d8b275f6914ed21152a0eab94efbb80e03083cb95
6
+ metadata.gz: 5d20a391aee1d3338f08ecddb104cca25411626787bec16a2c0a25e125efa6bbee91f79350a919afcca7d6443fac62ca34d2f2da20985e1eae3b59c73e6f6b7f
7
+ data.tar.gz: 93d1ffe829d5fb3f591b9ef5244c013f4268d982f8e148893439b7788d8422f99e1449577fd708e753cb26db9029db1a08a1e46e8db0d12860e23db4124a8a82
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
@@ -1,4 +1,5 @@
1
1
  untitled document.xls
2
+ untitled document.csv
2
3
  test.xls
3
4
  compare*.xls
4
5
  sharepoint_download_excel.*
@@ -14,4 +15,6 @@ untitled document.xlsx*
14
15
  .DS_Store
15
16
  doc
16
17
  private_*
17
- test_private_*
18
+ test_private_*
19
+ coverage
20
+ .byebug_history
data/.ruby-version CHANGED
@@ -1 +1 @@
1
- 2.6.0
1
+ 3.2.1
data/.travis.yml CHANGED
@@ -4,10 +4,10 @@ env:
4
4
  sudo: false
5
5
  language: ruby
6
6
  rvm:
7
- - 2.3.0
8
- - 2.4.0
9
- - 2.5.0
10
- - 2.6.0
7
+ - 2.5.3
8
+ - 2.6.3
9
+ - 2.7.1
10
+ - 3.0.2
11
11
  before_install:
12
12
  - gem install bundler
13
13
  before_script:
data/CHANGELOG.md ADDED
@@ -0,0 +1,16 @@
1
+ # Changelog
2
+
3
+ ### 0.9.0 (in progress)
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
+
7
+ ### 0.8.1
8
+
9
+ * Adopted [Standard](https://github.com/testdouble/standard) for code formatting
10
+
11
+ ### 0.8.0
12
+
13
+ * Dropped support for ruby < 2.3.0
14
+ * Added support for 2.6.0
15
+ * Stripping strings before calling to_sym (possibly breaking, as symbols can be used to address columns)
16
+ * Started maintaining a changelog
data/Gemfile CHANGED
@@ -1,6 +1,8 @@
1
- source "http://rubygems.org"
1
+ # frozen_string_literal: true
2
+
3
+ source "https://rubygems.org"
2
4
 
3
5
  # Specify your gem's dependencies in workbook.gemspec
4
6
 
5
7
  gemspec
6
- gem 'rubyzip', :require => 'zip/zip'
8
+ gem "rubyzip", require: "zip/zip"
data/README.md CHANGED
@@ -1,7 +1,10 @@
1
1
  # Workbook
2
- [![Code Climate](https://codeclimate.com/github/murb/workbook.png)](https://codeclimate.com/github/murb/workbook) [![Build Status](https://travis-ci.org/murb/workbook.svg?branch=master)](https://travis-ci.org/murb/workbook) [![Gem Version](https://badge.fury.io/rb/workbook.svg)](http://badge.fury.io/rb/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 base Array class, and hence walks and quacks 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.
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 an the first Sheet and Table (if one doesn't exist it is created on the fly).
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 for ruby 1.9, 2.0 and 2.1. Most of it works with 1.8.7 and jruby but not all tests give equal results.
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,14 +1,16 @@
1
- require 'rake'
2
- require 'rake/testtask'
3
- require 'bundler'
1
+ # frozen_string_literal: true
2
+
3
+ require "rake"
4
+ require "rake/testtask"
5
+ require "bundler"
4
6
  require "bundler/gem_tasks"
5
7
 
6
- #Bundler::GemHelper.install_tasks
8
+ # Bundler::GemHelper.install_tasks
7
9
 
8
- task :default => [:test]
10
+ task default: [:test]
9
11
 
10
12
  Rake::TestTask.new do |t|
11
13
  t.libs << "test"
12
- t.test_files = FileList['test/test*.rb','test/writers/test*.rb']
14
+ t.test_files = FileList["test/test*.rb", "test/writers/test*.rb"]
13
15
  t.verbose = false
14
- end
16
+ end
data/lib/workbook/book.rb CHANGED
@@ -1,17 +1,18 @@
1
- # -*- encoding : utf-8 -*-
2
1
  # frozen_string_literal: true
3
- require 'open-uri'
4
- require 'workbook/writers/xls_writer'
5
- require 'workbook/writers/xlsx_writer'
6
- require 'workbook/writers/html_writer'
7
- require 'workbook/readers/xls_reader'
8
- require 'workbook/readers/xls_shared'
9
- require 'workbook/readers/xlsx_reader'
10
- require 'workbook/readers/ods_reader'
11
- require 'workbook/readers/csv_reader'
12
- require 'workbook/readers/txt_reader'
13
- require 'workbook/readers/txt_reader'
14
- require 'workbook/modules/diff_sort'
2
+ # frozen_string_literal: true
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"
15
16
 
16
17
  module Workbook
17
18
  # The Book class is the container of sheets. It can be inialized by either the standard initalizer or the open method. The
@@ -33,8 +34,9 @@ module Workbook
33
34
  "CDF V2 Document, No summary info"
34
35
  ]
35
36
 
36
- class Book < Array
37
-
37
+ class Book
38
+ include Enumerable
39
+ extend Forwardable
38
40
 
39
41
  include Workbook::Readers::XlsShared
40
42
  include Workbook::Writers::XlsWriter
@@ -47,14 +49,13 @@ module Workbook
47
49
  include Workbook::Readers::TxtReader
48
50
  include Workbook::Modules::BookDiffSort
49
51
 
52
+ delegate [:last, :pop, :delete_at, :each, :[]] => :@sheets
53
+
50
54
  # @param [Workbook::Sheet, Array] sheet create a new workbook based on an existing sheet, or initialize a sheet based on the array
51
55
  # @return [Workbook::Book]
52
- def initialize sheet=nil
53
- if sheet.is_a? Workbook::Sheet
54
- self.push sheet
55
- elsif sheet
56
- self.push Workbook::Sheet.new(sheet, self, {})
57
- end
56
+ def initialize sheet = nil
57
+ @sheets = []
58
+ push sheet if sheet
58
59
  end
59
60
 
60
61
  # @return [Workbook::Template] returns the template describing how the document should be/is formatted
@@ -72,37 +73,51 @@ module Workbook
72
73
  #
73
74
  # @return [String] the title of the workbook
74
75
  def title
75
- (defined?(@title) and !@title.nil?) ? @title : "untitled document"
76
+ defined?(@title) && !@title.nil? ? @title : "untitled document"
76
77
  end
77
78
 
78
- def title= t
79
- @title = t
80
- end
79
+ attr_writer :title
81
80
 
82
81
  # Push (like in array) a sheet to the workbook (parameter is optional, default is a new sheet)
83
82
  #
84
- # @param [Workbook::Sheet] sheet
85
- def push sheet=Workbook::Sheet.new
86
- super(sheet)
87
- sheet.book=(self)
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
88
90
  end
89
91
 
90
- # << (like in array) a sheet to the workbook (parameter is optional, default is a new sheet)
92
+ # Inserts a new Table at the specified index
91
93
  #
92
- # @param [Workbook::Sheet] sheet
93
- def << sheet=Workbook::Sheet.new
94
- sheet = Workbook::Sheet.new(sheet) unless sheet.is_a? Workbook::Sheet
95
- super(sheet)
96
- sheet.book=(self)
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
97
102
  end
98
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
99
115
 
100
116
  # Sheet returns the first sheet of a workbook, or an empty one.
101
117
  #
102
118
  # @return [Workbook::Sheet] The first sheet, and creates an empty one if one doesn't exists
103
119
  def sheet
104
- push Workbook::Sheet.new unless first
105
- first
120
+ first || push
106
121
  end
107
122
 
108
123
  # If the first sheet has any contents
@@ -117,9 +132,9 @@ module Workbook
117
132
  # @param [String] filename a string with a reference to the file to be opened
118
133
  # @param [String] extension an optional string enforcing a certain parser (based on the file extension, e.g. 'txt', 'csv' or 'xls')
119
134
  # @return [Workbook::Book] A new instance, based on the filename
120
- def import filename, extension=nil, options={}
121
- extension = file_extension(filename) unless extension
122
- if ['txt','csv','xml'].include?(extension)
135
+ def import filename, extension = nil, options = {}
136
+ extension ||= file_extension(filename)
137
+ if ["txt", "csv", "xml"].include?(extension)
123
138
  open_text filename, extension, options
124
139
  else
125
140
  open_binary filename, extension, options
@@ -131,9 +146,9 @@ module Workbook
131
146
  # @param [String] filename a string with a reference to the file to be opened
132
147
  # @param [String] extension an optional string enforcing a certain parser (based on the file extension, e.g. 'txt', 'csv' or 'xls')
133
148
  # @return [Workbook::Book] A new instance, based on the filename
134
- def open_binary filename, extension=nil, options={}
135
- extension = file_extension(filename) unless extension
136
- f = open(filename)
149
+ def open_binary filename, extension = nil, options = {}
150
+ extension ||= file_extension(filename)
151
+ f = File.open(filename)
137
152
  send("load_#{extension}".to_sym, f, options)
138
153
  end
139
154
 
@@ -141,9 +156,9 @@ module Workbook
141
156
  #
142
157
  # @param [String] filename a string with a reference to the file to be opened
143
158
  # @param [String] extension an optional string enforcing a certain parser (based on the file extension, e.g. 'txt', 'csv' or 'xls')
144
- def open_text filename, extension=nil, options={}
145
- extension = file_extension(filename) unless extension
146
- 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)
147
162
  send("load_#{extension}".to_sym, t, options)
148
163
  end
149
164
 
@@ -151,21 +166,20 @@ module Workbook
151
166
  #
152
167
  # @param [String] filename a string with a reference to the file to be written to
153
168
  # @param [Hash] options depends on the writer chosen by the file's filetype
154
- def write filename, options={}
169
+ def write filename, options = {}
155
170
  extension = file_extension(filename)
156
171
  send("write_to_#{extension}".to_sym, filename, options)
157
172
  end
158
173
 
159
-
160
174
  # Helper method to convert text in a file to UTF-8
161
175
  #
162
176
  # @param [String] text a string to convert
163
177
  def text_to_utf8 text
164
- unless text.valid_encoding? and text.encoding == "UTF-8"
178
+ unless text.valid_encoding? && (text.encoding == "UTF-8")
165
179
  # TODO: had some ruby 1.9 problems with rchardet ... but ideally it or a similar functionality will be reintroduced
166
180
  source_encoding = text.valid_encoding? ? text.encoding : "US-ASCII"
167
- text = text.encode('UTF-8', source_encoding, {:invalid=>:replace, :undef=>:replace, :replace=>""})
168
- text = text.gsub("\u0000","") # TODO: this cleanup of nil values isn't supposed to be needed...
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...
169
183
  end
170
184
  text
171
185
  end
@@ -174,16 +188,16 @@ module Workbook
174
188
  #
175
189
  # @return [String] The file extension
176
190
  def file_extension(filename)
177
- ext = File.extname(filename).gsub('.','').downcase if filename
191
+ ext = File.extname(filename).delete(".").downcase if filename
178
192
  # for remote files which has asset id after extension
179
- ext.split('?')[0]
193
+ ext.split("?")[0]
180
194
  end
181
195
 
182
196
  # Load the CSV data contained in the given StringIO or String object
183
197
  #
184
198
  # @param [StringIO] stringio_or_string StringIO stream or String object, with data in CSV format
185
199
  # @param [Symbol] filetype (currently only :csv or :txt), indicating the format of the first parameter
186
- def read(stringio_or_string, filetype, options={})
200
+ def read(stringio_or_string, filetype, options = {})
187
201
  raise ArgumentError.new("The filetype parameter should be either :csv or :txt") unless [:csv, :txt].include?(filetype)
188
202
  t = stringio_or_string.respond_to?(:read) ? stringio_or_string.read : stringio_or_string.to_s
189
203
  t = text_to_utf8(t)
@@ -195,7 +209,7 @@ module Workbook
195
209
  # @param [Integer] index the index of the sheet
196
210
  def create_or_open_sheet_at index
197
211
  s = self[index]
198
- s = self[index] = Workbook::Sheet.new if s == nil
212
+ s = self[index] = Workbook::Sheet.new if s.nil?
199
213
  s.book = self
200
214
  s
201
215
  end
@@ -206,10 +220,10 @@ module Workbook
206
220
  # @param [String] filename of the document
207
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.
208
222
  # @return [Workbook::Book] A new instance, based on the filename
209
- def open filename, extension=nil
210
- wb = self.new
223
+ def open filename, extension = nil
224
+ wb = new
211
225
  wb.import filename, extension
212
- return wb
226
+ wb
213
227
  end
214
228
 
215
229
  # Create an instance from the given stream or string, which should be in CSV or TXT format
@@ -217,12 +231,11 @@ module Workbook
217
231
  # @param [StringIO] stringio_or_string StringIO stream or String object, with data in CSV or TXT format
218
232
  # @param [Symbol] filetype (currently only :csv or :txt), indicating the format of the first parameter
219
233
  # @return [Workbook::Book] A new instance
220
- def read stringio_or_string, filetype, options={}
221
- wb = self.new
234
+ def read stringio_or_string, filetype, options = {}
235
+ wb = new
222
236
  wb.read(stringio_or_string, filetype, options)
223
237
  wb
224
238
  end
225
-
226
239
  end
227
240
  end
228
241
  end
data/lib/workbook/cell.rb CHANGED
@@ -1,18 +1,65 @@
1
- # -*- encoding : utf-8 -*-
2
1
  # frozen_string_literal: true
3
- require 'workbook/modules/cell'
2
+ # frozen_string_literal: true
3
+
4
+ require "workbook/modules/cell"
4
5
 
5
6
  module Workbook
6
7
  class Cell
7
- include Workbook::Modules::Cell
8
-
9
- # @param [Numeric,String,Time,Date,TrueClass,FalseClass,NilClass] value a valid value
10
- # @param [Hash] options a reference to :format (Workbook::Format) can be specified
11
- def initialize value=nil, options={}
12
- self.format = options[:format] if options[:format]
13
- self.row = options[:row]
14
- self.value = value
15
- @to_sym = nil
16
- end
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
17
64
  end
18
65
  end
@@ -1,33 +1,39 @@
1
- # -*- encoding : utf-8 -*-
2
1
  # frozen_string_literal: true
2
+ # frozen_string_literal: true
3
+
3
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.
4
6
 
5
- # Column helps us to store general properties of a column, and lets us easily perform operations on values within a column
6
7
  class Column
7
- attr_accessor :limit, :width #character limit
8
+ include Enumerable
9
+ extend Forwardable
10
+
11
+ delegate [:first, :last, :each, :count, :include?, :index, :to_csv, :length, :empty?] => :cells
8
12
 
9
- def initialize(table=nil, options={})
13
+ attr_accessor :limit, :width # character limit
14
+
15
+ def initialize(table = nil, options = {})
10
16
  self.table = table
11
- options.each{ |k,v| self.public_send("#{k}=",v) }
17
+ options.each { |k, v| public_send("#{k}=", v) }
12
18
  end
13
19
 
14
20
  # Returns column type, either :primary_key, :string, :text, :integer, :float, :decimal, :datetime, :date, :binary, :boolean
15
21
  def column_type
16
22
  return @column_type if defined?(@column_type)
17
- ind = self.index
23
+ ind = index
18
24
  table[1..500].each do |row|
19
- if row[ind] and row[ind].cell_type
25
+ if row[ind]&.cell_type
20
26
  cel_column_type = row[ind].cell_type
21
- if !defined?(@column_type) or @column_type.nil?
27
+ if !defined?(@column_type) || @column_type.nil?
22
28
  @column_type = cel_column_type
23
- elsif cel_column_type == @column_type or cel_column_type == :nil
29
+ elsif (cel_column_type == @column_type) || (cel_column_type == :nil)
24
30
  else
25
31
  @column_type = :string
26
32
  break
27
33
  end
28
34
  end
29
35
  end
30
- return @column_type
36
+ @column_type
31
37
  end
32
38
 
33
39
  # Returns index of the column within the table's columns-set
@@ -39,14 +45,12 @@ module Workbook
39
45
  # Set the table this column belongs to
40
46
  # @param [Workbook::Table] table this column belongs to
41
47
  def table= table
42
- 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
43
49
  @table = table
44
50
  end
45
51
 
46
52
  # @return [Workbook::Table]
47
- def table
48
- @table
49
- end
53
+ attr_reader :table
50
54
 
51
55
  def column_type= column_type
52
56
  if [:primary_key, :string, :text, :integer, :float, :decimal, :datetime, :date, :binary, :boolean].include? column_type
@@ -57,25 +61,26 @@ module Workbook
57
61
  end
58
62
  end
59
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
+
60
69
  def head_value
61
- begin
62
- table.header[index].value
63
- rescue
64
- return "!noheader!"
65
- end
70
+ table.header[index].value
71
+ rescue
72
+ "!noheader!"
66
73
  end
67
74
 
68
75
  def inspect
69
76
  "<Workbook::Column index=#{index}, header=#{head_value}>"
70
77
  end
71
78
 
72
- #default cell
73
- def default
74
- return @default
75
- end
79
+ # default cell
80
+ attr_reader :default
76
81
 
77
82
  def default= value
78
- @default = value if value.class == Cell
83
+ @default = value if value.instance_of?(Cell)
79
84
  @default = Cell.new(value)
80
85
  end
81
86
 
@@ -84,13 +89,12 @@ module Workbook
84
89
  # @param [String] string that typically identifies a column
85
90
  # @return [Integer]
86
91
  def alpha_index_to_number_index string
87
- string.upcase!
88
92
  sum = 0
89
- string.chars.each_with_index do | char, char_index|
90
- sum = sum * 26 + char.unpack('U')[0]-64
93
+ string.upcase.chars.each_with_index do |char, char_index|
94
+ sum = sum * 26 + char.unpack1("U") - 64
91
95
  end
92
- return sum-1
96
+ sum - 1
93
97
  end
94
98
  end
95
99
  end
96
- end
100
+ end