dreader 0.1.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 +7 -0
- data/.gitignore +8 -0
- data/Gemfile +6 -0
- data/LICENSE.txt +21 -0
- data/README.md +117 -0
- data/Rakefile +2 -0
- data/bin/console +14 -0
- data/bin/setup +8 -0
- data/dreader.gemspec +36 -0
- data/lib/dreader/version.rb +3 -0
- data/lib/dreader.rb +151 -0
- metadata +105 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: be77a7a58ae4abcdcba7d3b734bc64f2cf756efd34bab78c30a4b0633fa6027a
|
4
|
+
data.tar.gz: d06cc4188e57c2e93297cece38b09b992cfeacad1f8cbbe6e645534965c45f4d
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: b3cbaeb434fea0a8f3c7dafcf2a096fd28b18deef69e66360be27eeff4cd8b0b42ea0f080f3fab85f01f26c90f4ce35424668fac855d15f6f0be8c1f25a9bc9c
|
7
|
+
data.tar.gz: 4da7939fa5e05ae685ad21f21a120067f4e4ddb5370b8171a37a7c00407f69300b162f0779cb69816ce3f8141f606c992226bf1125428911f1b7cd5dcb8a6b8d
|
data/.gitignore
ADDED
data/Gemfile
ADDED
data/LICENSE.txt
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
The MIT License (MIT)
|
2
|
+
|
3
|
+
Copyright (c) 2018 Adolfo Villafiorita
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
7
|
+
in the Software without restriction, including without limitation the rights
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
10
|
+
furnished to do so, subject to the following conditions:
|
11
|
+
|
12
|
+
The above copyright notice and this permission notice shall be included in
|
13
|
+
all copies or substantial portions of the Software.
|
14
|
+
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
21
|
+
THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,117 @@
|
|
1
|
+
# Dreader
|
2
|
+
|
3
|
+
A simple DSL built on top of `roo` to read and process tabular data (CSV,
|
4
|
+
LibreOffice, Excel).
|
5
|
+
|
6
|
+
Use this gem to specify the structure of some tabular data you want to
|
7
|
+
process. The input data can be in CSV, LibreOffice, and Excel. Each row can
|
8
|
+
then be passed to a block of code you define.
|
9
|
+
|
10
|
+
The gem can thus be used to check, process, import data. We use it to import data into
|
11
|
+
Rails application, but the gem can used in any Ruby application.
|
12
|
+
|
13
|
+
The gem should be relatively easy to use, despite its name: *dread* stands for
|
14
|
+
*d*ata *r*eader.
|
15
|
+
|
16
|
+
The gem depends on `roo`.
|
17
|
+
|
18
|
+
## Installation
|
19
|
+
|
20
|
+
Add this line to your application's Gemfile:
|
21
|
+
|
22
|
+
```ruby
|
23
|
+
gem 'dreader'
|
24
|
+
```
|
25
|
+
|
26
|
+
And then execute:
|
27
|
+
|
28
|
+
$ bundle
|
29
|
+
|
30
|
+
Or install it yourself as:
|
31
|
+
|
32
|
+
$ gem install dreader
|
33
|
+
|
34
|
+
## Usage
|
35
|
+
|
36
|
+
```
|
37
|
+
i = Dreader::Engine.new
|
38
|
+
|
39
|
+
i.options do
|
40
|
+
start_at 1
|
41
|
+
end
|
42
|
+
|
43
|
+
# first column is called name
|
44
|
+
# :name should be non nil and of length greater than 0
|
45
|
+
i.column :name do
|
46
|
+
check do |x|
|
47
|
+
x and x.length > 0
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
# second column is called surname
|
52
|
+
# :surname should be non nil and of length greater than 0
|
53
|
+
i.column :surname do
|
54
|
+
check do |x|
|
55
|
+
x and x.length > 0
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
# third column is called birthdate
|
60
|
+
# :name should be non nil and of length greater than 0
|
61
|
+
i.column :birthdate do
|
62
|
+
check do |x|
|
63
|
+
x.class == Date
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
# fourth column is called age
|
68
|
+
# we make it into an integer
|
69
|
+
# age should be greater than 0
|
70
|
+
i.column :age do
|
71
|
+
process do |r|
|
72
|
+
r.to_i
|
73
|
+
end
|
74
|
+
|
75
|
+
check do |r|
|
76
|
+
r > 0
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
# when we decide to process the file, for every row
|
81
|
+
# we print the value of the name and the value of the surname
|
82
|
+
i.mapping do |r|
|
83
|
+
puts "#{r[:name][:value]} #{r[:surname][:value]}"
|
84
|
+
end
|
85
|
+
|
86
|
+
i.read "/home/adolfo/Desktop/a.ods"
|
87
|
+
i.process
|
88
|
+
```
|
89
|
+
|
90
|
+
## Known Bugs and Limitations
|
91
|
+
|
92
|
+
No known bugs and an unknown number of unknown bugs.
|
93
|
+
|
94
|
+
(See the open issues for the known bugs.)
|
95
|
+
|
96
|
+
|
97
|
+
## Development
|
98
|
+
|
99
|
+
After checking out the repo, run `bin/setup` to install dependencies. You can
|
100
|
+
also run `bin/console` for an interactive prompt that will allow you to
|
101
|
+
experiment.
|
102
|
+
|
103
|
+
To install this gem onto your local machine, run `bundle exec rake
|
104
|
+
install`. To release a new version, update the version number in `version.rb`,
|
105
|
+
and then run `bundle exec rake release`, which will create a git tag for the
|
106
|
+
version, push git commits and tags, and push the `.gem` file to
|
107
|
+
[rubygems.org](https://rubygems.org).
|
108
|
+
|
109
|
+
## Contributing
|
110
|
+
|
111
|
+
Bug reports and pull requests are welcome on GitHub at
|
112
|
+
https://github.com/avillafiorita/dreader.
|
113
|
+
|
114
|
+
## License
|
115
|
+
|
116
|
+
The gem is available as open source under the terms of the [MIT
|
117
|
+
License](https://opensource.org/licenses/MIT).
|
data/Rakefile
ADDED
data/bin/console
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require "bundler/setup"
|
4
|
+
require "dreader"
|
5
|
+
|
6
|
+
# You can add fixtures and/or initialization code here to make experimenting
|
7
|
+
# with your gem easier. You can also use a different console, if you like.
|
8
|
+
|
9
|
+
# (If you use this, don't forget to add pry to your Gemfile!)
|
10
|
+
# require "pry"
|
11
|
+
# Pry.start
|
12
|
+
|
13
|
+
require "irb"
|
14
|
+
IRB.start(__FILE__)
|
data/bin/setup
ADDED
data/dreader.gemspec
ADDED
@@ -0,0 +1,36 @@
|
|
1
|
+
|
2
|
+
lib = File.expand_path("../lib", __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require "dreader/version"
|
5
|
+
|
6
|
+
Gem::Specification.new do |spec|
|
7
|
+
spec.name = "dreader"
|
8
|
+
spec.version = Dreader::VERSION
|
9
|
+
spec.authors = ["Adolfo Villafiorita"]
|
10
|
+
spec.email = ["adolfo.villafiorita@ict4g.net"]
|
11
|
+
|
12
|
+
spec.summary = %q{Process and import data from cvs and spreadsheets}
|
13
|
+
spec.description = %q{Use this gem to specify the structure of some tabular data
|
14
|
+
you want to process. The input data can be in CSV, LibreOffice, and Excel. Each row
|
15
|
+
can then be passed to a block of code you define.
|
16
|
+
|
17
|
+
The gem can thus be used to check, process, import data. We use it to import data into
|
18
|
+
Rails application, but the gem can used in any Ruby application.
|
19
|
+
|
20
|
+
The gem should be relatively easy to use, despite its name. (Dread
|
21
|
+
stands for *d*ata *r*eader)}
|
22
|
+
spec.homepage = "http://github.com/avillafiorita/dreader"
|
23
|
+
spec.license = "MIT"
|
24
|
+
|
25
|
+
spec.files = `git ls-files -z`.split("\x0").reject do |f|
|
26
|
+
f.match(%r{^(test|spec|features)/})
|
27
|
+
end
|
28
|
+
spec.bindir = "exe"
|
29
|
+
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
30
|
+
spec.require_paths = ["lib"]
|
31
|
+
|
32
|
+
spec.add_development_dependency "bundler", "~> 1.16"
|
33
|
+
spec.add_development_dependency "rake", "~> 10.0"
|
34
|
+
|
35
|
+
spec.add_runtime_dependency "roo"
|
36
|
+
end
|
data/lib/dreader.rb
ADDED
@@ -0,0 +1,151 @@
|
|
1
|
+
require "dreader/version"
|
2
|
+
|
3
|
+
module Dreader
|
4
|
+
# service class to implement the column DSL language
|
5
|
+
class Column
|
6
|
+
def process &block
|
7
|
+
@process = block
|
8
|
+
end
|
9
|
+
|
10
|
+
def check &block
|
11
|
+
@check = block
|
12
|
+
end
|
13
|
+
|
14
|
+
def to_hash
|
15
|
+
{process: @process, check: @check }
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
# service class to implement the options DSL language
|
20
|
+
class Options
|
21
|
+
def initialize
|
22
|
+
@attributes = {}
|
23
|
+
end
|
24
|
+
|
25
|
+
def method_missing(name, *args, &block)
|
26
|
+
@attributes[name] = args[0]
|
27
|
+
end
|
28
|
+
|
29
|
+
def to_hash
|
30
|
+
@attributes
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
#
|
35
|
+
# This is where the real stuff begins
|
36
|
+
#
|
37
|
+
class Engine
|
38
|
+
|
39
|
+
# readable for debugging purposes
|
40
|
+
# the options we passed
|
41
|
+
attr_reader :options
|
42
|
+
# the specification of the columns to process
|
43
|
+
attr_reader :colspec
|
44
|
+
# the data we read
|
45
|
+
attr_reader :array
|
46
|
+
|
47
|
+
def initialize
|
48
|
+
@options = {}
|
49
|
+
@colspec = []
|
50
|
+
end
|
51
|
+
|
52
|
+
# define a DSL for options
|
53
|
+
# any string is processed as an option and it ends up in the
|
54
|
+
# @options hash
|
55
|
+
def options &block
|
56
|
+
options = Options.new
|
57
|
+
options.instance_eval(&block)
|
58
|
+
|
59
|
+
@options = options.to_hash
|
60
|
+
end
|
61
|
+
|
62
|
+
# define a DSL for column specification
|
63
|
+
# - `name` is the name of the column
|
64
|
+
# - `block` contains two declarations, `process` and `check`, which are
|
65
|
+
# used, respectively, to make a cell into the desired data and to check
|
66
|
+
# whether the desired data is ok
|
67
|
+
def column name, &block
|
68
|
+
column = Column.new
|
69
|
+
column.instance_eval(&block)
|
70
|
+
|
71
|
+
@colspec << column.to_hash.merge({name: name})
|
72
|
+
end
|
73
|
+
|
74
|
+
# define what we do with each line we read
|
75
|
+
# - `block` is the code which takes as input a `row` and processes
|
76
|
+
# `row` is a hash in which each spreadsheet cell is accessible under
|
77
|
+
# the column names. Each cell has the following values:
|
78
|
+
# :value, :error, :row_number, :col_number
|
79
|
+
def mapping &block
|
80
|
+
@mapping = block
|
81
|
+
end
|
82
|
+
|
83
|
+
# read a file and store it internally
|
84
|
+
# return the data we read in the form of an array of hashes
|
85
|
+
def read filename=nil
|
86
|
+
spreadsheet = self.open_spreadsheet filename || @options[:filename]
|
87
|
+
sheet = spreadsheet.sheet(@options[:sheet] || 0)
|
88
|
+
|
89
|
+
@array = Array.new
|
90
|
+
@errors = Array.new
|
91
|
+
first_row = @options[:start_at] || 1
|
92
|
+
(first_row..spreadsheet.last_row).each do |row_number|
|
93
|
+
row = spreadsheet.row(row_number)
|
94
|
+
|
95
|
+
r = Hash.new
|
96
|
+
@colspec.each_with_index do |colspec, index|
|
97
|
+
colname = colspec[:name]
|
98
|
+
|
99
|
+
r[colname] = Hash.new
|
100
|
+
|
101
|
+
r[colname][:row_number] = row_number
|
102
|
+
r[colname][:col_number] = index + 1
|
103
|
+
|
104
|
+
r[colname][:value] = value = colspec[:process] ? colspec[:process].call(row[index]) : row[index]
|
105
|
+
|
106
|
+
if colspec[:check] and not colspec[:check].call(value) then
|
107
|
+
r[colname][:error] = true
|
108
|
+
@errors << "Error: value \"#{row[index]}\" for #{colname} at row #{row_number} (col #{index + 1}) is incorrect"
|
109
|
+
else
|
110
|
+
r[colname][:error] = false
|
111
|
+
end
|
112
|
+
end
|
113
|
+
|
114
|
+
@array << r
|
115
|
+
end
|
116
|
+
|
117
|
+
@array
|
118
|
+
end
|
119
|
+
|
120
|
+
# return an array of strings with all the errors we have encounterd
|
121
|
+
# an empty array is a good news
|
122
|
+
def errors
|
123
|
+
@errors
|
124
|
+
end
|
125
|
+
|
126
|
+
# apply the mapping code to the array
|
127
|
+
# it makes sense to invoke it only
|
128
|
+
def process
|
129
|
+
@array.each do |r|
|
130
|
+
@mapping.call(r)
|
131
|
+
end
|
132
|
+
end
|
133
|
+
|
134
|
+
def to_s
|
135
|
+
@array.to_s
|
136
|
+
end
|
137
|
+
|
138
|
+
private
|
139
|
+
|
140
|
+
def self.open_spreadsheet(filename)
|
141
|
+
case File.extname(filename)
|
142
|
+
when ".csv" then Csv.new(filename)
|
143
|
+
when ".ods" then Roo::OpenOffice.new(filename)
|
144
|
+
when ".xls" then Roo::Excel.new(filename)
|
145
|
+
when ".xlsx" then Roo::Excelx.new(filename)
|
146
|
+
else raise "Unknown file type: #{filename}"
|
147
|
+
end
|
148
|
+
end
|
149
|
+
end
|
150
|
+
|
151
|
+
end
|
metadata
ADDED
@@ -0,0 +1,105 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: dreader
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.1
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Adolfo Villafiorita
|
8
|
+
autorequire:
|
9
|
+
bindir: exe
|
10
|
+
cert_chain: []
|
11
|
+
date: 2018-03-22 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: bundler
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '1.16'
|
20
|
+
type: :development
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - "~>"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '1.16'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: rake
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - "~>"
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '10.0'
|
34
|
+
type: :development
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - "~>"
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '10.0'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: roo
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - ">="
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '0'
|
48
|
+
type: :runtime
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - ">="
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '0'
|
55
|
+
description: |-
|
56
|
+
Use this gem to specify the structure of some tabular data
|
57
|
+
you want to process. The input data can be in CSV, LibreOffice, and Excel. Each row
|
58
|
+
can then be passed to a block of code you define.
|
59
|
+
|
60
|
+
The gem can thus be used to check, process, import data. We use it to import data into
|
61
|
+
Rails application, but the gem can used in any Ruby application.
|
62
|
+
|
63
|
+
The gem should be relatively easy to use, despite its name. (Dread
|
64
|
+
stands for *d*ata *r*eader)
|
65
|
+
email:
|
66
|
+
- adolfo.villafiorita@ict4g.net
|
67
|
+
executables: []
|
68
|
+
extensions: []
|
69
|
+
extra_rdoc_files: []
|
70
|
+
files:
|
71
|
+
- ".gitignore"
|
72
|
+
- Gemfile
|
73
|
+
- LICENSE.txt
|
74
|
+
- README.md
|
75
|
+
- Rakefile
|
76
|
+
- bin/console
|
77
|
+
- bin/setup
|
78
|
+
- dreader.gemspec
|
79
|
+
- lib/dreader.rb
|
80
|
+
- lib/dreader/version.rb
|
81
|
+
homepage: http://github.com/avillafiorita/dreader
|
82
|
+
licenses:
|
83
|
+
- MIT
|
84
|
+
metadata: {}
|
85
|
+
post_install_message:
|
86
|
+
rdoc_options: []
|
87
|
+
require_paths:
|
88
|
+
- lib
|
89
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
90
|
+
requirements:
|
91
|
+
- - ">="
|
92
|
+
- !ruby/object:Gem::Version
|
93
|
+
version: '0'
|
94
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
95
|
+
requirements:
|
96
|
+
- - ">="
|
97
|
+
- !ruby/object:Gem::Version
|
98
|
+
version: '0'
|
99
|
+
requirements: []
|
100
|
+
rubyforge_project:
|
101
|
+
rubygems_version: 2.7.3
|
102
|
+
signing_key:
|
103
|
+
specification_version: 4
|
104
|
+
summary: Process and import data from cvs and spreadsheets
|
105
|
+
test_files: []
|