goodsheet 0.4.0 → 0.4.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: aef27ae57a44343de4b43b8118c3a4dba7940021
4
- data.tar.gz: ccd478aad49271a61e1e4278cbfd95ea9a226b17
3
+ metadata.gz: b602fb68bc8d91fbc2004a2fc5dc021e26ef25cc
4
+ data.tar.gz: 7ccf288b4183c2d84ecdc5f22afbdfd572824dd5
5
5
  SHA512:
6
- metadata.gz: cf0b9d857e4eb5a66cbf72a6c205e1ab4f517fd93dbd40e42382e1b1f34d0b0e74813bdf8bb5e3e48c554933297ccc31160d39e83e2d4b311825ddf73c32d897
7
- data.tar.gz: f866ccb2f33ffa9618f12c597a1ab4c9d88282eaf6ffd0485d0e262f78cc506c424a58cc97f2de569e385aa88e2f517b3ee85fd443a955c35e9fe4c808bd7e6e
6
+ metadata.gz: 81da028ed30bdd2e27616fcff01fe313e8eb38884e098121518eff2be24cad1ec538f5641442ec18d08f896bf756f640baec21352a898716555d236e0e6821b1
7
+ data.tar.gz: 0b85bba8e877f4907ec5a601ecb3fd482358d0cdb32d174467495a4334e0d8a138dbc8865abb3f901410f371b3a36bacca77bb4bad9f5320472774ba49fda363
data/README.md CHANGED
@@ -30,7 +30,8 @@ Given a spreadsheet:
30
30
  ```ruby
31
31
  ss = Goodsheet::Spreadsheet.new("example.xls")
32
32
  res = ss.read do
33
- column_names :filename => 0, :size => 1, :created_at => 3, :updated_at => 4 # ignore 'description' column
33
+ column_names :filename => 0, :size => 1, :created_at => 3, :updated_at => 4 # i want to ignore 'description' column
34
+ column_defaults :filename => "UNKNOWN"
34
35
  validates :filename, :presence => true
35
36
  validates :size, :presence => true, :numericality => { :greater_than_or_equal_to => 0.0 }
36
37
  validate :order_of_dates
@@ -126,14 +127,21 @@ ss.rows_wo_skipped # => except the skipped ones, aliased by `rows` method
126
127
 
127
128
  #### Reading and validate
128
129
 
129
- Use the `validate` and `read` methods to perform validation and reading. Note that the reading function include a validation call.
130
+ Use the `validate` and `read` methods to perform validation and reading. Note that the reading function include the validation step.
130
131
  Pass the previously seen `options` hash and a block to `validate`/`read` method.
131
- Inside the block you define columns names and indexes you want to validate/read using the `column_names` method. You can use one of these 4 forms (and their effect is the same):
132
+ Inside the block you define columns names and indexes you want to validate/read using the `column_names` method. You can use one of these 4 forms (and their effect is identical):
132
133
  - `column_names :a => 0, :b => 1, :c => 3`
133
134
  - `column_names 0 => :a, 1 => :b, 3 => :c`
134
135
  - `column_names [:a, :b, nil, :c]`
135
136
  - `column_names :a, :b, nil, :c`
136
137
 
138
+ Use the `column_defaults` method to specify the value to set when the corresponding cell hold a nil value (is empty). Like the previous method, the following forms are identical:
139
+ - `column_defaults :a => 0.0, :b => 0.0, :c => "UNKNOWN"`
140
+ - `column_defaults 0 => 0.0, 1 => 0.0, 3 => "UNKNOWN"`
141
+ - `column_defaults [0.0, 0.0, "UNKNOWN"]`
142
+ - `column_defaults 0.0, 0.0, "UNKNOWN"`
143
+ The `column_defaults` macro overwrite the read/validate `:force_nil` option.
144
+
137
145
  Aside from define the columns settings, into block you define the validation rules.
138
146
  Refer to the [official guide](http://guides.rubyonrails.org/active_record_validations.html) and [ROR Api](http://api.rubyonrails.org/classes/ActiveModel/Validations/ClassMethods.html)
139
147
 
@@ -2,6 +2,7 @@
2
2
  lib = File.expand_path('../lib', __FILE__)
3
3
  $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
4
  require 'goodsheet/version'
5
+ require 'date'
5
6
 
6
7
  Gem::Specification.new do |spec|
7
8
  spec.name = "goodsheet"
@@ -12,7 +13,7 @@ Gem::Specification.new do |spec|
12
13
  spec.summary = "Extract and validate data from a spreadsheet"
13
14
  spec.homepage = "https://github.com/iwan/goodsheet"
14
15
  spec.license = "MIT"
15
- spec.date = '2013-07-19'
16
+ spec.date = Date.today.to_s
16
17
  spec.files = `git ls-files`.split($/)
17
18
  spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
18
19
  spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
@@ -23,6 +24,6 @@ Gem::Specification.new do |spec|
23
24
  spec.add_development_dependency "rake"
24
25
 
25
26
  spec.add_dependency('roo', '>= 1.12.1') # https://github.com/Empact/roo
26
- spec.add_dependency('activemodel', '>= 3.2.14')
27
+ spec.add_dependency('activemodel', '~> 3.2')
27
28
  spec.add_dependency('google_drive')
28
29
  end
@@ -0,0 +1,10 @@
1
+ class Object
2
+ def chrono(msg, &block)
3
+ puts "--------- starting #{msg} -------->"
4
+ t = Time.now
5
+ yield
6
+ delta_t = Time.now-t
7
+ puts "<-------- #{msg} takes #{delta_t}s"
8
+ return delta_t
9
+ end
10
+ end
@@ -6,7 +6,7 @@ module Goodsheet
6
6
  include ActiveModel::Validations
7
7
 
8
8
  class << self
9
- attr_accessor :keys, :defaults
9
+ attr_accessor :keys, :defaults, :defaults_attributes
10
10
  end
11
11
  # @keys = {} # idx => key: {0=>:name, 1=>:quantity, 2=>:price, 3=>:total, 6=>:password}
12
12
  # @defaults = {} # name => default_value
@@ -28,6 +28,7 @@ module Goodsheet
28
28
  c = Class.new(self) do
29
29
  @keys = {} # idx => key: {0=>:name, 1=>:quantity, 2=>:price, 3=>:total, 6=>:password}
30
30
  @defaults = {} # name => default_value
31
+ @defaults_attributes = nil # name => default_value
31
32
  end
32
33
  c.class_eval(&block)
33
34
  c
@@ -35,16 +36,29 @@ module Goodsheet
35
36
 
36
37
  # using indexes: defaults 1 => 0.0, 2 => ""
37
38
  # using names: defaults :qty => 0.0, :name => ""
38
-
39
39
  def self.column_defaults(*attr)
40
40
  raise ArgumentError, 'You have to pass at least one attribute' if attr.empty?
41
- if attr[0].is_a? Array
41
+ if self.keys.empty?
42
+ self.defaults_attributes = attr
43
+ else
44
+ self.defaults_attributes = nil
45
+ self.set_defaults(attr)
46
+ end
47
+ end
48
+
49
+ def self.set_defaults(attr)
50
+ if attr[0].is_a? Array # column_defaults [0.0, nil, "Unknown"]
51
+ # @defaults = Hash[attr[0].map.with_index{|v, i| [self.keys[i], v]}]
42
52
  @defaults = Hash[attr[0].map.with_index{|v, i| [self.keys[i], v]}]
43
53
 
44
- elsif attr[0].is_a? Hash
54
+ elsif attr[0].is_a? Hash # column_defaults 0 => 0.0, 1 => nil, 2 => "Unknown"
55
+ # --or-- column_defaults :size => 0.0, :weight => nil, :name => "Unknown"
56
+
57
+ # @defaults = Hash[attr[0].to_a.collect{|a| [(a[0].is_a?(Fixnum)) ? (self.keys[a[0]]) : a[0], a[1]]}]
45
58
  @defaults = Hash[attr[0].to_a.collect{|a| [(a[0].is_a?(Fixnum)) ? (self.keys[a[0]]) : a[0], a[1]]}]
46
59
 
47
- else
60
+ else # column_defaults 0.0, nil, "Unknown"
61
+ # @defaults = Hash[attr.map.with_index{|v, i| [self.keys[i], v]}]
48
62
  @defaults = Hash[attr.map.with_index{|v, i| [self.keys[i], v]}]
49
63
  end
50
64
  end
@@ -58,30 +72,21 @@ module Goodsheet
58
72
  # at the position, or simply put the list of names.
59
73
  # The positions are 0-based.
60
74
  def self.column_names(*attr)
61
- # def self.column_names(param)
62
75
  @keys = {}
63
76
  raise ArgumentError, 'You have to pass at least one attribute' if attr.empty?
64
77
  if attr[0].is_a? Array
65
78
  attr[0].each_with_index do |name, idx|
66
79
  self.set_key_pair(idx, name) if name
67
- # if name
68
- # self.keys[idx] = name
69
- # attr_accessor name
70
- # end
71
80
  end
72
81
 
73
82
  elsif attr[0].is_a? Hash
74
83
  if attr[0].first[0].is_a? Integer
75
84
  attr[0].each do |idx, name|
76
85
  self.set_key_pair(idx, name)
77
- # self.keys[idx] = name
78
- # attr_accessor name
79
86
  end
80
87
  else
81
88
  attr[0].each do |name, idx|
82
89
  self.set_key_pair(idx, name)
83
- # self.keys[idx] = name
84
- # attr_accessor name
85
90
  end
86
91
  end
87
92
 
@@ -90,12 +95,13 @@ module Goodsheet
90
95
  if name
91
96
  name = name.to_s.gsub(" ", "_").to_sym unless name.is_a? Symbol
92
97
  self.set_key_pair(idx, name)
93
- # self.keys[idx] = name
94
- # attr_accessor name
95
98
  end
96
99
  end
97
100
  end
98
101
 
102
+ if !self.defaults_attributes.nil?
103
+ self.set_defaults(self.defaults_attributes)
104
+ end
99
105
  end
100
106
 
101
107
 
@@ -1,3 +1,3 @@
1
1
  module Goodsheet
2
- VERSION = "0.4.0"
2
+ VERSION = "0.4.1"
3
3
  end
@@ -0,0 +1,147 @@
1
+ require 'test/unit'
2
+ require 'goodsheet'
3
+
4
+ class TestDefaults < Test::Unit::TestCase
5
+
6
+ def setup
7
+ filepath = File.dirname(__FILE__) + "/fixtures/for_defaults.xls"
8
+ @ss = Goodsheet::Spreadsheet.new(filepath, :skip => 1)
9
+ end
10
+
11
+
12
+
13
+ def test_invalid
14
+ res = @ss.read do
15
+ column_names 0 => :name, 1 => :number
16
+ validates :name, :presence => true
17
+ validates :number, :numericality => true
18
+ end
19
+ assert(res.invalid?)
20
+
21
+ res = @ss.read do
22
+ column_names 0 => :name, 1 => :number
23
+ column_defaults 0 => "UNKNOWN"
24
+ validates :name, :presence => true
25
+ validates :number, :numericality => true
26
+ end
27
+ assert(res.invalid?)
28
+
29
+ res = @ss.read do
30
+ column_names 0 => :name, 1 => :number
31
+ column_defaults 1 => 0.0
32
+ validates :name, :presence => true
33
+ validates :number, :numericality => true
34
+ end
35
+ assert(res.invalid?)
36
+ end
37
+
38
+
39
+
40
+ def test_force_nil_vs_defaults
41
+ res = @ss.read(:force_nil => 0.0) do
42
+ column_names 0 => :name, 1 => :number
43
+ validates :name, :presence => true
44
+ validates :number, :numericality => true
45
+ end
46
+ assert(res.valid?)
47
+ assert_equal(["Joshua Baney", "Libby Meiers", "Dean Murdoch", 0.0, "Esmeralda Erben"], res.values[:name])
48
+ assert_equal([3.0, 2.0, 0.0, 8.0, 1.0], res.values[:number])
49
+
50
+ res = @ss.read(:force_nil => "foo") do
51
+ column_names 0 => :name, 1 => :number
52
+ validates :name, :presence => true
53
+ validates :number, :numericality => true
54
+ end
55
+ assert(res.invalid?)
56
+ assert_equal(["Joshua Baney", "Libby Meiers", "Dean Murdoch", "foo", "Esmeralda Erben"], res.values[:name])
57
+ assert_equal([3.0, 2.0, "foo", 8.0, 1.0], res.values[:number])
58
+
59
+
60
+ res = @ss.read(:force_nil => 1.0) do
61
+ column_names 0 => :name, 1 => :number
62
+ column_defaults 0 => "UNKNOWN", 1 => 10.0
63
+ validates :name, :presence => true
64
+ validates :number, :numericality => true
65
+ end
66
+ assert(res.valid?)
67
+ assert_equal(["Joshua Baney", "Libby Meiers", "Dean Murdoch", "UNKNOWN", "Esmeralda Erben"], res.values[:name])
68
+ assert_equal([3.0, 2.0, 10.0, 8.0, 1.0], res.values[:number])
69
+ end
70
+
71
+
72
+
73
+ def test_values_correctness
74
+ res = @ss.read do
75
+ column_names 0 => :name, 1 => :number
76
+ column_defaults 0 => "UNKNOWN", 1 => 0.0
77
+ validates :name, :presence => true
78
+ validates :number, :numericality => true
79
+ end
80
+ assert(res.valid?)
81
+ assert_equal(["Joshua Baney", "Libby Meiers", "Dean Murdoch", "UNKNOWN", "Esmeralda Erben"], res.values[:name])
82
+ assert_equal([3.0, 2.0, 0.0, 8.0, 1.0], res.values[:number])
83
+ end
84
+
85
+
86
+
87
+ def test_not_existing_column
88
+ res = @ss.read do
89
+ column_names 0 => :name, 1 => :number, 2 => :fake
90
+ column_defaults 0 => "UNKNOWN", 1 => 0.0
91
+ validates :name, :presence => true
92
+ validates :number, :numericality => true
93
+ end
94
+ assert(res.valid?)
95
+ assert_equal([nil, nil, nil, nil, nil], res.values[:fake])
96
+
97
+ res = @ss.read do
98
+ column_names 0 => :name, 1 => :number, 2 => :fake
99
+ column_defaults 0 => "UNKNOWN", 1 => 0.0
100
+ validates :name, :presence => true
101
+ validates :number, :numericality => true
102
+ validates :fake, :presence => true
103
+ end
104
+ assert(res.invalid?)
105
+
106
+ res1 = @ss.read do
107
+ column_names 0 => :name, 1 => :number, 2 => :fake
108
+ column_defaults 0 => "UNKNOWN", 1 => 0.0, 2 => "EMPTY"
109
+ validates :name, :presence => true
110
+ validates :number, :numericality => true
111
+ validates :fake, :presence => true
112
+ end
113
+ assert(res1.valid?)
114
+ end
115
+
116
+
117
+
118
+ def test_column_defaults_formats
119
+ res_1 = @ss.read do
120
+ column_names :name, :number
121
+ column_defaults ["UNKNOWN", 0.0]
122
+ validates :name, :presence => true
123
+ validates :number, :numericality => true
124
+ end
125
+ assert(res_1.valid?)
126
+
127
+ res_2 = @ss.read do
128
+ column_names :name, :number
129
+ column_defaults "UNKNOWN", 0.0
130
+ validates :name, :presence => true
131
+ validates :number, :numericality => true
132
+ end
133
+ assert(res_2.valid?)
134
+ assert_equal(res_1.values, res_2.values)
135
+
136
+ res_3 = @ss.read do
137
+ column_names 0 => :name, 1 => :number
138
+ column_defaults 1 => 0.0, 0 => "UNKNOWN"
139
+ validates :name, :presence => true
140
+ validates :number, :numericality => true
141
+ end
142
+ assert(res_3.valid?)
143
+ assert_equal(res_1.values, res_3.values)
144
+ end
145
+
146
+
147
+ end
@@ -0,0 +1,130 @@
1
+ require 'test/unit'
2
+ require 'goodsheet'
3
+
4
+ # test the functionality of column_defaults macro, when used before column_names macro
5
+ class TestDefaults < Test::Unit::TestCase
6
+
7
+ def setup
8
+ filepath = File.dirname(__FILE__) + "/fixtures/for_defaults.xls"
9
+ @ss = Goodsheet::Spreadsheet.new(filepath, :skip => 1)
10
+ end
11
+
12
+
13
+ def test_values_correctness
14
+ res = @ss.read do
15
+ column_defaults 0 => "UNKNOWN", 1 => 0.0
16
+ column_names 0 => :name, 1 => :number
17
+ validates :name, :presence => true
18
+ validates :number, :numericality => true
19
+ end
20
+ assert(res.valid?)
21
+ assert_equal(["Joshua Baney", "Libby Meiers", "Dean Murdoch", "UNKNOWN", "Esmeralda Erben"], res.values[:name])
22
+ assert_equal([3.0, 2.0, 0.0, 8.0, 1.0], res.values[:number])
23
+ end
24
+
25
+
26
+ def test_invalid
27
+ res = @ss.read do
28
+ column_names 0 => :name, 1 => :number
29
+ validates :name, :presence => true
30
+ validates :number, :numericality => true
31
+ end
32
+ assert(res.invalid?)
33
+
34
+ res = @ss.read do
35
+ column_defaults 0 => "UNKNOWN"
36
+ column_names 0 => :name, 1 => :number
37
+ validates :name, :presence => true
38
+ validates :number, :numericality => true
39
+ end
40
+ assert(res.invalid?)
41
+
42
+ res = @ss.read do
43
+ column_defaults 1 => 0.0
44
+ column_names 0 => :name, 1 => :number
45
+ validates :name, :presence => true
46
+ validates :number, :numericality => true
47
+ end
48
+ assert(res.invalid?)
49
+ end
50
+
51
+
52
+
53
+ def test_force_nil_vs_defaults
54
+ res = @ss.read(:force_nil => 1.0) do
55
+ column_defaults 0 => "UNKNOWN", 1 => 10.0
56
+ column_names 0 => :name, 1 => :number
57
+ validates :name, :presence => true
58
+ validates :number, :numericality => true
59
+ end
60
+ assert(res.valid?)
61
+ assert_equal(["Joshua Baney", "Libby Meiers", "Dean Murdoch", "UNKNOWN", "Esmeralda Erben"], res.values[:name])
62
+ assert_equal([3.0, 2.0, 10.0, 8.0, 1.0], res.values[:number])
63
+ end
64
+
65
+
66
+
67
+
68
+
69
+
70
+ def test_not_existing_column
71
+ res = @ss.read do
72
+ column_defaults 0 => "UNKNOWN", 1 => 0.0
73
+ column_names 0 => :name, 1 => :number, 2 => :fake
74
+ validates :name, :presence => true
75
+ validates :number, :numericality => true
76
+ end
77
+ assert(res.valid?)
78
+ assert_equal([nil, nil, nil, nil, nil], res.values[:fake])
79
+
80
+ res = @ss.read do
81
+ column_defaults 0 => "UNKNOWN", 1 => 0.0
82
+ column_names 0 => :name, 1 => :number, 2 => :fake
83
+ validates :name, :presence => true
84
+ validates :number, :numericality => true
85
+ validates :fake, :presence => true
86
+ end
87
+ assert(res.invalid?)
88
+
89
+ res1 = @ss.read do
90
+ column_defaults 0 => "UNKNOWN", 1 => 0.0, 2 => "EMPTY"
91
+ column_names 0 => :name, 1 => :number, 2 => :fake
92
+ validates :name, :presence => true
93
+ validates :number, :numericality => true
94
+ validates :fake, :presence => true
95
+ end
96
+ assert(res1.valid?)
97
+ end
98
+
99
+
100
+
101
+ def test_column_defaults_formats
102
+ res_1 = @ss.read do
103
+ column_defaults ["UNKNOWN", 0.0]
104
+ column_names :name, :number
105
+ validates :name, :presence => true
106
+ validates :number, :numericality => true
107
+ end
108
+ assert(res_1.valid?)
109
+
110
+ res_2 = @ss.read do
111
+ column_defaults "UNKNOWN", 0.0
112
+ column_names :name, :number
113
+ validates :name, :presence => true
114
+ validates :number, :numericality => true
115
+ end
116
+ assert(res_2.valid?)
117
+ assert_equal(res_1.values, res_2.values)
118
+
119
+ res_3 = @ss.read do
120
+ column_defaults 1 => 0.0, 0 => "UNKNOWN"
121
+ column_names 0 => :name, 1 => :number
122
+ validates :name, :presence => true
123
+ validates :number, :numericality => true
124
+ end
125
+ assert(res_3.valid?)
126
+ assert_equal(res_1.values, res_3.values)
127
+ end
128
+
129
+
130
+ end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: goodsheet
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.4.0
4
+ version: 0.4.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Iwan Buetti
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2013-07-19 00:00:00.000000000 Z
11
+ date: 2013-10-29 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -56,16 +56,16 @@ dependencies:
56
56
  name: activemodel
57
57
  requirement: !ruby/object:Gem::Requirement
58
58
  requirements:
59
- - - '>='
59
+ - - ~>
60
60
  - !ruby/object:Gem::Version
61
- version: 3.2.14
61
+ version: '3.2'
62
62
  type: :runtime
63
63
  prerelease: false
64
64
  version_requirements: !ruby/object:Gem::Requirement
65
65
  requirements:
66
- - - '>='
66
+ - - ~>
67
67
  - !ruby/object:Gem::Version
68
- version: 3.2.14
68
+ version: '3.2'
69
69
  - !ruby/object:Gem::Dependency
70
70
  name: google_drive
71
71
  requirement: !ruby/object:Gem::Requirement
@@ -96,6 +96,7 @@ files:
96
96
  - goodsheet.gemspec
97
97
  - img/img_01.png
98
98
  - lib/goodsheet.rb
99
+ - lib/goodsheet/aux.rb
99
100
  - lib/goodsheet/exceptions.rb
100
101
  - lib/goodsheet/read_result.rb
101
102
  - lib/goodsheet/row.rb
@@ -106,12 +107,15 @@ files:
106
107
  - notes.txt
107
108
  - test/fixtures/example.xls
108
109
  - test/fixtures/fixtures_template.xlsx
110
+ - test/fixtures/for_defaults.xls
109
111
  - test/fixtures/ss_01.xls
110
112
  - test/fixtures/ss_02.csv
111
113
  - test/fixtures/ss_02.ods
112
114
  - test/fixtures/ss_02.xls
113
115
  - test/fixtures/ss_02.xlsx
114
116
  - test/fixtures/ss_04.xlsx
117
+ - test/test_defaults.rb
118
+ - test/test_defaults_2.rb
115
119
  - test/test_row.rb
116
120
  - test/test_spreadsheet_01.rb
117
121
  - test/test_spreadsheet_02.rb
@@ -143,12 +147,15 @@ summary: Extract and validate data from a spreadsheet
143
147
  test_files:
144
148
  - test/fixtures/example.xls
145
149
  - test/fixtures/fixtures_template.xlsx
150
+ - test/fixtures/for_defaults.xls
146
151
  - test/fixtures/ss_01.xls
147
152
  - test/fixtures/ss_02.csv
148
153
  - test/fixtures/ss_02.ods
149
154
  - test/fixtures/ss_02.xls
150
155
  - test/fixtures/ss_02.xlsx
151
156
  - test/fixtures/ss_04.xlsx
157
+ - test/test_defaults.rb
158
+ - test/test_defaults_2.rb
152
159
  - test/test_row.rb
153
160
  - test/test_spreadsheet_01.rb
154
161
  - test/test_spreadsheet_02.rb