honey_format 0.5.0 → 0.6.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 3f11a451917cde22eb1749f01e42e12d4bfc3314f0dd42692f27100c452557ab
4
- data.tar.gz: 4ad3a5e3be4a82e26fb3715c50011b5f7cc26069ac74058763cc4d097d1f7f0d
3
+ metadata.gz: 6ec17df72ebcb22be2365a454c19632f6ee22becc155a525bf66a010f7eec4b2
4
+ data.tar.gz: b05efbc59d1af2da443fd4c3e72cf573d9fd43b292b644336299411e705a77e3
5
5
  SHA512:
6
- metadata.gz: 63090f5e515480669c3dc2a74882e4fc4aba303eb7f2f0e71fbeb67a7f9ccf9f5b0cf592a07af8890e79da2f682ce9f6622be672a141219e1471d559f1ac9223
7
- data.tar.gz: 9439ebcfc40892fb57ac3cdca5f74f6c2ac58e0972b5200a6678194376c5063b4cc1083fde94f68c42c302fd720124c6ff3878cbd6b5d5546e92d38c0d4fcc87
6
+ metadata.gz: b802e64d2033b5ea9881b30142e88f9d326e7d89416deadd7aa3c2f49c6da3f5b7a03fda057a802a9cebff28c72d5c75cfe48e9fa3a93e68ac808beb480b3d42
7
+ data.tar.gz: 71682b5a17dae461bbdabece49219e76be07241494b3606849ec5e7198bcf9e6f8e470a0e5a857ff879d5cc48ea796214a93d3ac0793cffb3feb29842e15486e
data/.gitignore CHANGED
@@ -8,4 +8,5 @@
8
8
  /spec/reports/
9
9
  /tmp/
10
10
  benchmark.csv
11
+ benchmark*.csv
11
12
  .byebug_history
data/.travis.yml CHANGED
@@ -3,4 +3,5 @@ rvm:
3
3
  - 2.3.0
4
4
  - 2.4.0
5
5
  - 2.5.0
6
+ - 2.6.0-preview1
6
7
  before_install: gem install bundler -v 1.16.1
data/CHANGELOG.md CHANGED
@@ -1,3 +1,13 @@
1
+ # v0.6.0
2
+
3
+ * Add `CSV#to_csv` ([PR#2](https://github.com/buren/honey_format/pull/2))
4
+ * `csv#rows` returns an instance of `Rows` instead of `Array`
5
+
6
+ # v0.3.0 - v0.5.0
7
+
8
+ * Add CSV `row_builder` option
9
+ * ...
10
+
1
11
  # v0.2.0
2
12
 
3
13
  * More explicit exception classes
data/README.md CHANGED
@@ -49,13 +49,22 @@ user.id # => "1"
49
49
  user.username # => "buren"
50
50
  ```
51
51
 
52
+ Custom row builder
52
53
  ```ruby
53
54
  csv_string = "Id, Username\n 1, buren"
54
- uppercase_strings = ->(o) { o.is_a?(String) ? o.upcase : o }
55
- csv = HoneyFormat::CSV.new(csv_string, row_builder: uppercase_strings)
55
+ upcase_builder = ->(o) { o.is_a?(String) ? o.upcase : o }
56
+ csv = HoneyFormat::CSV.new(csv_string, row_builder: upcase_builder)
56
57
  csv.rows # => [#<struct id="1", username="BUREN">]
57
58
  ```
58
59
 
60
+ Output CSV
61
+ ```ruby
62
+ csv_string = "Id, Username\n 1, buren"
63
+ csv = HoneyFormat::CSV.new(csv_string)
64
+ csv.rows.each { |row| row.id = nil }
65
+ csv.to_csv # => "Id, Username\n,buren\n"
66
+ ```
67
+
59
68
  Validate CSV header
60
69
  ```ruby
61
70
  csv_string = "Id, Username\n 1, buren"
@@ -95,33 +104,25 @@ If you want to see more usage examples check out the `spec/` directory.
95
104
 
96
105
  _Note_: This gem, adds some overhead to parsing a CSV string. I've included some benchmarks below, your mileage may vary..
97
106
 
98
- Benchmarks, using the `benchmark-ips` gem, CSV with 11 columns in MBP 2013 OSX 10.10.
99
-
100
- 124KB (~1000 lines )
107
+ You can run the benchmarks yourself:
101
108
 
102
109
  ```
103
- Calculating -------------------------------------
104
- stdlib CSV 6.000 i/100ms
105
- HoneyFormat::CSV 5.000 i/100ms
106
- -------------------------------------------------
107
- stdlib CSV 64.236 (± 4.7%) i/s - 642.000
108
- HoneyFormat::CSV 52.762 (± 5.7%) i/s - 530.000
109
-
110
- Comparison:
111
- stdlib CSV: 64.2 i/s
112
- HoneyFormat::CSV: 52.8 i/s - 1.22x slower
110
+ $ bin/benchmark file.csv
113
111
  ```
114
112
 
115
- 20MB (~180k lines)
113
+ 204KB (1k lines)
116
114
 
117
115
  ```
118
- Comparison:
119
- stdlib CSV: 0.3 i/s
120
- HoneyFormat::CSV: 0.3 i/s - 1.26x slower
116
+ stdlib CSV: 48.9 i/s
117
+ HoneyFormat::CSV: 34.5 i/s - 1.41x slower
121
118
  ```
122
119
 
123
- See `bin/benchmark` for details.
124
- Run benchmark: `bin/benchmark`.
120
+ 19MB (100k lines)
121
+
122
+ ```
123
+ stdlib CSV: 0.4 i/s
124
+ HoneyFormat::CSV: 0.3 i/s - 1.41x slower
125
+ ```
125
126
 
126
127
  ## Development
127
128
 
data/bin/benchmark CHANGED
@@ -5,12 +5,12 @@ require 'honey_format'
5
5
  require 'benchmark/ips'
6
6
  require 'csv'
7
7
 
8
- # Assumes that you have a file "benchmark.csv" in your current directory
9
- csv = File.read('benchmark-20mb.csv')
8
+ path = ARGV.first || fail(ArgumentError, '<path_to_csv> argument must be provided')
9
+ csv = File.read(path)
10
10
 
11
11
  Benchmark.ips do |x|
12
- x.time = 10
13
- x.warmup = 2
12
+ x.time = 30
13
+ x.warmup = 5
14
14
 
15
15
  x.report('stdlib CSV') { CSV.parse(csv) }
16
16
  x.report('HoneyFormat::CSV') { HoneyFormat::CSV.new(csv).rows }
data/honey_format.gemspec CHANGED
@@ -23,4 +23,5 @@ Gem::Specification.new do |spec|
23
23
  spec.add_development_dependency 'benchmark-ips'
24
24
  spec.add_development_dependency 'rspec'
25
25
  spec.add_development_dependency 'simplecov'
26
+ spec.add_development_dependency 'byebug'
26
27
  end
@@ -1,5 +1,7 @@
1
1
  module HoneyFormat
2
+ # Header column converter
2
3
  module ConvertHeaderValue
4
+ # Replace map
3
5
  REPLACE_MAP = [
4
6
  [/ \(/, '('],
5
7
  [/ \[/, '['],
@@ -17,9 +17,9 @@ module HoneyFormat
17
17
  # @raise [UnknownCSVHeaderColumnError] raised when column is not in valid list.
18
18
  def initialize(csv, delimiter: ',', header: nil, valid_columns: :all, header_converter: ConvertHeaderValue, row_builder: nil)
19
19
  csv = ::CSV.parse(csv, col_sep: delimiter)
20
- @csv_body = csv
21
- @header = Header.new(header || csv.shift, valid: valid_columns, converter: header_converter)
22
- @row_builder = row_builder
20
+ header_row = header || csv.shift
21
+ @header = Header.new(header_row, valid: valid_columns, converter: header_converter)
22
+ @rows = Rows.new(csv, columns, builder: row_builder)
23
23
  end
24
24
 
25
25
  # @return [Array] of strings for sanitized header.
@@ -35,12 +35,17 @@ module HoneyFormat
35
35
  # @return [Array] of rows.
36
36
  # @raise [InvalidRowLengthError] raised when there are more row elements longer than columns
37
37
  def rows
38
- @rows ||= Rows.new(@csv_body, columns, builder: @row_builder).to_a
38
+ @rows
39
39
  end
40
40
 
41
41
  # @yield [row] block to receive the row.
42
42
  def each_row
43
43
  rows.each { |row| yield(row) }
44
44
  end
45
+
46
+ # @return [String] CSV-string representation.
47
+ def to_csv
48
+ header.to_csv + @rows.to_csv
49
+ end
45
50
  end
46
51
  end
@@ -23,5 +23,10 @@ module HoneyFormat
23
23
  def columns
24
24
  @columns.to_a
25
25
  end
26
+
27
+ # @return [String] CSV-string representation.
28
+ def to_csv
29
+ columns.to_csv
30
+ end
26
31
  end
27
32
  end
@@ -1,15 +1,12 @@
1
+ require 'honey_format/row_builder'
2
+
1
3
  module HoneyFormat
2
4
  # Holds data for a single row.
3
5
  class Row
4
- class RowBuilder < Struct
5
- def self.call(row)
6
- new(*row)
7
- end
8
- end
9
-
10
6
  # Returns a new instance of Row.
11
7
  # @return [Row] a new instance of Row.
12
8
  # @param [Array] columns an array of symbols.
9
+ # @param builder [#call, #to_csv] optional row builder
13
10
  # @raise [EmptyColumnsError] raised when there are no columns.
14
11
  # @example Create new row
15
12
  # Row.new!([:id])
@@ -0,0 +1,21 @@
1
+ module HoneyFormat
2
+ # Default row builder
3
+ class RowBuilder < Struct
4
+ # @return [Struct] returns an instantiated Struct representing a row
5
+ def self.call(row)
6
+ new(*row)
7
+ end
8
+
9
+ # @return [String] CSV-string representation.
10
+ def to_csv
11
+ members.map do |column_name|
12
+ column = public_send(column_name)
13
+ if column.respond_to?(:to_csv)
14
+ column.to_csv
15
+ else
16
+ column.to_s
17
+ end
18
+ end.join(',') + "\n"
19
+ end
20
+ end
21
+ end
@@ -3,6 +3,8 @@ require 'honey_format/row'
3
3
  module HoneyFormat
4
4
  # Represents rows.
5
5
  class Rows
6
+ include Enumerable
7
+
6
8
  # Returns array of cleaned strings.
7
9
  # @return [Rows] new instance of Rows.
8
10
  # @param [Array] rows the array of rows.
@@ -11,12 +13,25 @@ module HoneyFormat
11
13
  @rows = prepare_rows(Row.new(columns, builder: builder), rows)
12
14
  end
13
15
 
16
+ # @yield [row] The given block will be passed every row.
17
+ # @yieldparam [Row] a row in the CSV file.
18
+ # @return [Enumerator]
19
+ # If no block is given, an enumerator object will be returned.
20
+ def each(&block)
21
+ @rows.each(&block)
22
+ end
23
+
14
24
  # Returns rows as array.
15
25
  # @return [Array] of rows.
16
26
  def to_a
17
27
  @rows
18
28
  end
19
29
 
30
+ # @return [String] CSV-string representation.
31
+ def to_csv
32
+ to_a.map(&:to_csv).join
33
+ end
34
+
20
35
  private
21
36
 
22
37
  def prepare_rows(builder, rows)
@@ -1,4 +1,4 @@
1
1
  module HoneyFormat
2
2
  # Gem version
3
- VERSION = '0.5.0'
3
+ VERSION = '0.6.0'
4
4
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: honey_format
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.5.0
4
+ version: 0.6.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Jacob Burenstam
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2018-05-04 00:00:00.000000000 Z
11
+ date: 2018-05-11 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -80,6 +80,20 @@ dependencies:
80
80
  - - ">="
81
81
  - !ruby/object:Gem::Version
82
82
  version: '0'
83
+ - !ruby/object:Gem::Dependency
84
+ name: byebug
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - ">="
88
+ - !ruby/object:Gem::Version
89
+ version: '0'
90
+ type: :development
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - ">="
95
+ - !ruby/object:Gem::Version
96
+ version: '0'
83
97
  description: Convert CSV to an array of objects with with ease. Create objects for
84
98
  each row with methods matching the column names. No dependencies other than Ruby
85
99
  stdlib.
@@ -109,6 +123,7 @@ files:
109
123
  - lib/honey_format/exceptions.rb
110
124
  - lib/honey_format/header.rb
111
125
  - lib/honey_format/row.rb
126
+ - lib/honey_format/row_builder.rb
112
127
  - lib/honey_format/rows.rb
113
128
  - lib/honey_format/sanitize.rb
114
129
  - lib/honey_format/version.rb