workbook 0.8.1 → 0.9.0

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 +8 -0
  7. data/Gemfile +2 -2
  8. data/README.md +9 -7
  9. data/Rakefile +6 -6
  10. data/json_test.json +1 -0
  11. data/lib/workbook/book.rb +73 -62
  12. data/lib/workbook/cell.rb +58 -13
  13. data/lib/workbook/column.rb +31 -28
  14. data/lib/workbook/format.rb +23 -24
  15. data/lib/workbook/generatetypes.rb +4 -4
  16. data/lib/workbook/modules/cache.rb +6 -7
  17. data/lib/workbook/modules/cell.rb +77 -100
  18. data/lib/workbook/modules/diff_sort.rb +92 -83
  19. data/lib/workbook/modules/raw_objects_storage.rb +6 -8
  20. data/lib/workbook/modules/type_parser.rb +30 -22
  21. data/lib/workbook/nil_value.rb +4 -9
  22. data/lib/workbook/readers/csv_reader.rb +7 -10
  23. data/lib/workbook/readers/ods_reader.rb +51 -50
  24. data/lib/workbook/readers/txt_reader.rb +6 -8
  25. data/lib/workbook/readers/xls_reader.rb +21 -33
  26. data/lib/workbook/readers/xls_shared.rb +106 -117
  27. data/lib/workbook/readers/xlsx_reader.rb +45 -46
  28. data/lib/workbook/row.rb +99 -84
  29. data/lib/workbook/sheet.rb +47 -38
  30. data/lib/workbook/table.rb +96 -72
  31. data/lib/workbook/template.rb +12 -15
  32. data/lib/workbook/types/false.rb +0 -1
  33. data/lib/workbook/types/nil.rb +0 -1
  34. data/lib/workbook/types/nil_class.rb +1 -1
  35. data/lib/workbook/types/numeric.rb +1 -1
  36. data/lib/workbook/types/string.rb +1 -1
  37. data/lib/workbook/types/time.rb +1 -1
  38. data/lib/workbook/types/true.rb +0 -1
  39. data/lib/workbook/types/true_class.rb +1 -1
  40. data/lib/workbook/version.rb +2 -3
  41. data/lib/workbook/writers/csv_table_writer.rb +10 -13
  42. data/lib/workbook/writers/html_writer.rb +34 -38
  43. data/lib/workbook/writers/json_table_writer.rb +8 -11
  44. data/lib/workbook/writers/xls_writer.rb +30 -36
  45. data/lib/workbook/writers/xlsx_writer.rb +45 -29
  46. data/lib/workbook.rb +16 -15
  47. data/test/artifacts/currency_test.ods +0 -0
  48. data/test/helper.rb +6 -5
  49. data/test/test_book.rb +41 -38
  50. data/test/test_column.rb +26 -24
  51. data/test/test_format.rb +51 -55
  52. data/test/test_functional.rb +7 -8
  53. data/test/test_modules_cache.rb +18 -17
  54. data/test/test_modules_cell.rb +55 -46
  55. data/test/test_modules_table_diff_sort.rb +55 -64
  56. data/test/test_modules_type_parser.rb +61 -31
  57. data/test/test_readers_csv_reader.rb +48 -42
  58. data/test/test_readers_ods_reader.rb +36 -31
  59. data/test/test_readers_txt_reader.rb +21 -23
  60. data/test/test_readers_xls_reader.rb +20 -23
  61. data/test/test_readers_xls_shared.rb +2 -3
  62. data/test/test_readers_xlsx_reader.rb +44 -37
  63. data/test/test_row.rb +105 -109
  64. data/test/test_sheet.rb +35 -41
  65. data/test/test_table.rb +82 -60
  66. data/test/test_template.rb +16 -15
  67. data/test/test_types_date.rb +4 -6
  68. data/test/test_writers_csv_writer.rb +24 -0
  69. data/test/test_writers_html_writer.rb +42 -41
  70. data/test/test_writers_json_writer.rb +16 -9
  71. data/test/test_writers_xls_writer.rb +50 -35
  72. data/test/test_writers_xlsx_writer.rb +62 -34
  73. data/workbook.gemspec +25 -27
  74. metadata +96 -42
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 87ff9d1b27ed349f1b788ec37cf0ca3e743353abf6281badaebd2a9a5efa4355
4
- data.tar.gz: 52f399ec0e3ea2acead3f918cf9b43b942dc158ee321e19239eff71563f4f6ba
3
+ metadata.gz: 898a4a79301299545d91cfdd5b5f1f261f4cde32337d4713256f21d894cc49f0
4
+ data.tar.gz: ee61cd9e3e3687092b5c8ca82e8aa10bf8f846553a3602ce3c46103b43ee4e9b
5
5
  SHA512:
6
- metadata.gz: 151d666f60f1edcb99ba8dfaa35d4cb8e6bebe33bcb3e15543f80f22b62593fa02dd8a45e74fd680260296f2a398008a07fc227dddaafa21958eb0a0a65f8cfb
7
- data.tar.gz: eb0fcf133fe88aed80b42c91e9c3cec2f94820c7fb33eda606b0f5c97f1d7cf1368f6de52508655790af0ebd03a5952e6099d8293b1a3329ffd13d156c20fb76
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
@@ -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.2
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 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
@@ -1,8 +1,8 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- source "http://rubygems.org"
3
+ source "https://rubygems.org"
4
4
 
5
5
  # Specify your gem's dependencies in workbook.gemspec
6
6
 
7
7
  gemspec
8
- 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,16 +1,16 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'rake'
4
- require 'rake/testtask'
5
- require 'bundler'
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 :default => [:test]
10
+ task default: [:test]
11
11
 
12
12
  Rake::TestTask.new do |t|
13
13
  t.libs << "test"
14
- t.test_files = FileList['test/test*.rb','test/writers/test*.rb']
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
- 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/readers/txt_reader'
16
- require 'workbook/modules/diff_sort'
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 < Array
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
- if sheet.is_a? Workbook::Sheet
56
- self.push sheet
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
- (defined?(@title) and !@title.nil?) ? @title : "untitled document"
76
+ defined?(@title) && !@title.nil? ? @title : "untitled document"
78
77
  end
79
78
 
80
- def title= t
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
- super(sheet)
89
- 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
90
90
  end
91
91
 
92
- # << (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
93
93
  #
94
- # @param [Workbook::Sheet] sheet
95
- def << sheet=Workbook::Sheet.new
96
- sheet = Workbook::Sheet.new(sheet) unless sheet.is_a? Workbook::Sheet
97
- super(sheet)
98
- 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
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
- push Workbook::Sheet.new unless first
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 = file_extension(filename) unless extension
124
- 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)
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 = file_extension(filename) unless 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 = file_extension(filename) unless 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? and text.encoding == "UTF-8"
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('UTF-8', source_encoding, {:invalid=>:replace, :undef=>:replace, :replace=>""})
170
- 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...
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).gsub('.','').downcase if filename
191
+ ext = File.extname(filename).delete(".").downcase if filename
180
192
  # for remote files which has asset id after extension
181
- ext.split('?')[0]
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 == nil
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 = self.new
223
+ def open filename, extension = nil
224
+ wb = new
213
225
  wb.import filename, extension
214
- return wb
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 = self.new
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
- require 'workbook/modules/cell'
3
+
4
+ require "workbook/modules/cell"
6
5
 
7
6
  module Workbook
8
7
  class Cell
9
- include Workbook::Modules::Cell
10
-
11
- # @param [Numeric,String,Time,Date,TrueClass,FalseClass,NilClass] value a valid value
12
- # @param [Hash] options a reference to :format (Workbook::Format) can be specified
13
- def initialize value=nil, options={}
14
- self.format = options[:format] if options[:format]
15
- self.row = options[:row]
16
- self.value = value
17
- @to_sym = nil
18
- 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
19
64
  end
20
65
  end
@@ -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
- 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
10
12
 
11
- def initialize(table=nil, options={})
13
+ attr_accessor :limit, :width # character limit
14
+
15
+ def initialize(table = nil, options = {})
12
16
  self.table = table
13
- options.each{ |k,v| self.public_send("#{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 = self.index
23
+ ind = index
20
24
  table[1..500].each do |row|
21
- if row[ind] and row[ind].cell_type
25
+ if row[ind]&.cell_type
22
26
  cel_column_type = row[ind].cell_type
23
- if !defined?(@column_type) or @column_type.nil?
27
+ if !defined?(@column_type) || @column_type.nil?
24
28
  @column_type = cel_column_type
25
- elsif cel_column_type == @column_type or cel_column_type == :nil
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
- return @column_type
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
- def table
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
- begin
64
- table.header[index].value
65
- rescue
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
- def default
76
- return @default
77
- end
79
+ # default cell
80
+ attr_reader :default
78
81
 
79
82
  def default= value
80
- @default = value if value.class == Cell
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 | char, char_index|
91
- 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
92
95
  end
93
- return sum-1
96
+ sum - 1
94
97
  end
95
98
  end
96
99
  end