rcsv_loader 0.0.1 → 0.2.0
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 +4 -4
- data/.travis.yml +2 -0
- data/lib/rcsv_loader/base.rb +11 -0
- data/lib/rcsv_loader/core.rb +137 -0
- data/lib/rcsv_loader/version.rb +1 -1
- data/lib/rcsv_loader/where.rb +50 -0
- data/lib/rcsv_loader.rb +1 -135
- data/spec/core_spec.rb +63 -0
- data/spec/rcsv_loader_spec.rb +27 -0
- metadata +7 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA1:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: f16383a5089660aaa8623b243f05a9cdc72dc363
|
|
4
|
+
data.tar.gz: 592ee577893e3f81f4ba869bf1c227f1e7cba056
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: ac77ebaaa41fe9c176b736953842de5c66a18752d000e3a312d5711b1d4094aa16d0432109b1de659bc24a064c3ae1cfd87736585da9281796885cb4c76385b4
|
|
7
|
+
data.tar.gz: af321f0a281ca5dd9d30a6443e1d349df33cf6f5e29f1f6678858be06ca37f6d4a34610eb07ab05451da89d179741f3b54cf56bab5929640497210a6026aab95
|
data/.travis.yml
CHANGED
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
require 'rcsv_loader/where'
|
|
2
|
+
|
|
3
|
+
module RCsvLoader
|
|
4
|
+
module Core
|
|
5
|
+
extend Forwardable
|
|
6
|
+
|
|
7
|
+
include Where
|
|
8
|
+
|
|
9
|
+
def self.included base
|
|
10
|
+
base.extend ClassMethods
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
module ClassMethods
|
|
14
|
+
#
|
|
15
|
+
# Laod a csv file
|
|
16
|
+
#
|
|
17
|
+
# options: The options for 'csv' which is Ruby's built-in library.
|
|
18
|
+
#
|
|
19
|
+
def load_csv file, options = {}
|
|
20
|
+
|
|
21
|
+
rows = CSV.readlines file, options
|
|
22
|
+
|
|
23
|
+
rows = yield rows if block_given?
|
|
24
|
+
|
|
25
|
+
self.new rows.map { |row| self::Row.new row }
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
attr_reader :headers
|
|
29
|
+
|
|
30
|
+
#
|
|
31
|
+
# Define accessor names for csv column.
|
|
32
|
+
#
|
|
33
|
+
def column column_name, alias_name = nil
|
|
34
|
+
alias_name = column_name.to_sym unless alias_name
|
|
35
|
+
@headers = all_headers
|
|
36
|
+
@headers.merge!(alias_name => column_name)
|
|
37
|
+
define_row(@headers)
|
|
38
|
+
|
|
39
|
+
@has_headers = true
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
#
|
|
43
|
+
# Define headers for no headers csv.
|
|
44
|
+
#
|
|
45
|
+
def insert_headers headers = []
|
|
46
|
+
@headers = Hash[headers.map.with_index { |e, i| [e, i] }]
|
|
47
|
+
define_row(@headers)
|
|
48
|
+
|
|
49
|
+
@has_headers = false
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
def headers?
|
|
53
|
+
!!@has_headers
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
private
|
|
57
|
+
#
|
|
58
|
+
# Get headers that include super class's one.
|
|
59
|
+
#
|
|
60
|
+
def all_headers current_class = nil
|
|
61
|
+
current_class ||= self
|
|
62
|
+
return {} if current_class == Object
|
|
63
|
+
current_header = current_class.headers || {}
|
|
64
|
+
return current_header.merge all_headers(current_class.superclass)
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
#
|
|
68
|
+
# Define a class which represent a row of csv.
|
|
69
|
+
#
|
|
70
|
+
def define_row headers
|
|
71
|
+
headers ||= {}
|
|
72
|
+
|
|
73
|
+
# get the superclass for Row
|
|
74
|
+
baseclass = if superclass.const_defined? :Row
|
|
75
|
+
superclass::Row
|
|
76
|
+
else
|
|
77
|
+
Object
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
# remove class definition
|
|
81
|
+
if const_defined? :Row and baseclass != self::Row
|
|
82
|
+
self.send :remove_const, :Row
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
# define Row class
|
|
86
|
+
const_set :Row, (Class.new(baseclass) do
|
|
87
|
+
|
|
88
|
+
attr_accessor *headers.keys
|
|
89
|
+
|
|
90
|
+
define_method :initialize do |line = {}|
|
|
91
|
+
headers.each do |k, v|
|
|
92
|
+
instance_variable_set "@#{k.to_s}", line[v]
|
|
93
|
+
end
|
|
94
|
+
end
|
|
95
|
+
|
|
96
|
+
define_method :to_csv do
|
|
97
|
+
CSV.generate_line headers.map { |k, v| self.send k }
|
|
98
|
+
end
|
|
99
|
+
|
|
100
|
+
end)
|
|
101
|
+
end
|
|
102
|
+
end
|
|
103
|
+
|
|
104
|
+
def_delegators :@rows, :+, :<<
|
|
105
|
+
|
|
106
|
+
def initialize rows = []
|
|
107
|
+
@rows = rows
|
|
108
|
+
end
|
|
109
|
+
|
|
110
|
+
def all
|
|
111
|
+
@rows
|
|
112
|
+
end
|
|
113
|
+
|
|
114
|
+
#
|
|
115
|
+
# Convert to csv string
|
|
116
|
+
#
|
|
117
|
+
# options: {
|
|
118
|
+
# headers: boolean
|
|
119
|
+
# }
|
|
120
|
+
#
|
|
121
|
+
def to_csv options = {}
|
|
122
|
+
csv = ""
|
|
123
|
+
csv += header_line if options[:headers].nil? or options[:headers]
|
|
124
|
+
csv += @rows.map(&:to_csv).join
|
|
125
|
+
end
|
|
126
|
+
|
|
127
|
+
private
|
|
128
|
+
|
|
129
|
+
#
|
|
130
|
+
# generate header line
|
|
131
|
+
#
|
|
132
|
+
def header_line
|
|
133
|
+
CSV.generate_line(self.class.headers.map { |k, v| self.class.headers? ? v.to_s : k.to_s })
|
|
134
|
+
end
|
|
135
|
+
|
|
136
|
+
end
|
|
137
|
+
end
|
data/lib/rcsv_loader/version.rb
CHANGED
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
module RCsvLoader
|
|
2
|
+
module Where
|
|
3
|
+
|
|
4
|
+
#
|
|
5
|
+
# params = {
|
|
6
|
+
# :#{accessor_name} => expected_value,
|
|
7
|
+
# ...
|
|
8
|
+
# }
|
|
9
|
+
#
|
|
10
|
+
# compare with '=='
|
|
11
|
+
#
|
|
12
|
+
# options = {
|
|
13
|
+
# :regexp => true
|
|
14
|
+
# }
|
|
15
|
+
#
|
|
16
|
+
# return empty array if the condition is invalid or couldn't find any rows.
|
|
17
|
+
#
|
|
18
|
+
def where conditions = {}, options = {}
|
|
19
|
+
rows = @rows || []
|
|
20
|
+
return rows if conditions.empty?
|
|
21
|
+
|
|
22
|
+
# filter the conditions.
|
|
23
|
+
c = conditions.select do |k, v|
|
|
24
|
+
self.class.headers.keys.any? { |key| key.to_s == k.to_s }
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
return [] if c.empty?
|
|
28
|
+
|
|
29
|
+
if options[:regexp]
|
|
30
|
+
where_with_regexp c
|
|
31
|
+
else
|
|
32
|
+
rows.select { |row| c.all? { |attr, con| (row.send attr) == con } }
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
private
|
|
38
|
+
|
|
39
|
+
#
|
|
40
|
+
# evaluate expression with #match
|
|
41
|
+
#
|
|
42
|
+
def where_with_regexp conditions = {}
|
|
43
|
+
rows = @rows || []
|
|
44
|
+
return rows if conditions.empty?
|
|
45
|
+
rows.select { |row| conditions.all? { |attr, con| (row.send attr).match con } }
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
end
|
|
49
|
+
end
|
|
50
|
+
|
data/lib/rcsv_loader.rb
CHANGED
|
@@ -2,139 +2,5 @@ require "rcsv_loader/version"
|
|
|
2
2
|
require 'csv'
|
|
3
3
|
|
|
4
4
|
module RCsvLoader
|
|
5
|
-
|
|
6
|
-
attr_reader :headers
|
|
7
|
-
|
|
8
|
-
#
|
|
9
|
-
# Define accessor names for csv column.
|
|
10
|
-
#
|
|
11
|
-
def column column_name, alias_name = nil
|
|
12
|
-
alias_name = column_name.to_sym unless alias_name
|
|
13
|
-
@headers = all_headers
|
|
14
|
-
@headers.merge!(alias_name => column_name)
|
|
15
|
-
define_row(@headers)
|
|
16
|
-
end
|
|
17
|
-
|
|
18
|
-
#
|
|
19
|
-
# Define headers for no headers csv.
|
|
20
|
-
#
|
|
21
|
-
def insert_headers headers = []
|
|
22
|
-
@headers = Hash[headers.map.with_index { |e, i| [e, i] }]
|
|
23
|
-
define_row(@headers)
|
|
24
|
-
end
|
|
25
|
-
|
|
26
|
-
class Base
|
|
27
|
-
extend RCsvLoader
|
|
28
|
-
extend Forwardable
|
|
29
|
-
|
|
30
|
-
#
|
|
31
|
-
# Laod a csv file
|
|
32
|
-
#
|
|
33
|
-
# options: The options for 'csv' which is Ruby's built-in library.
|
|
34
|
-
#
|
|
35
|
-
def self.load_csv file, options = {}
|
|
36
|
-
|
|
37
|
-
rows = CSV.readlines file, options
|
|
38
|
-
|
|
39
|
-
rows = yield rows if block_given?
|
|
40
|
-
|
|
41
|
-
self.new rows.map { |row| self::Row.new row }
|
|
42
|
-
end
|
|
43
|
-
|
|
44
|
-
def_delegators :@rows, :+, :<<
|
|
45
|
-
|
|
46
|
-
def initialize rows = []
|
|
47
|
-
@rows = rows
|
|
48
|
-
end
|
|
49
|
-
|
|
50
|
-
def all
|
|
51
|
-
@rows
|
|
52
|
-
end
|
|
53
|
-
|
|
54
|
-
#
|
|
55
|
-
# params = {
|
|
56
|
-
# :#{accessor_name} => expected_value,
|
|
57
|
-
# ...
|
|
58
|
-
# }
|
|
59
|
-
#
|
|
60
|
-
# compare with '=='
|
|
61
|
-
#
|
|
62
|
-
# return empty array if the condition is invalid or couldn't find any rows.
|
|
63
|
-
#
|
|
64
|
-
def where params = {}
|
|
65
|
-
return @rows if params.empty?
|
|
66
|
-
|
|
67
|
-
# filter the conditions.
|
|
68
|
-
params.select! do |k, v|
|
|
69
|
-
self.class.headers.keys.any? { |key| key.to_s == k.to_s }
|
|
70
|
-
end
|
|
71
|
-
|
|
72
|
-
return [] if params.empty?
|
|
73
|
-
|
|
74
|
-
@rows.select do |row|
|
|
75
|
-
params.all? { |attr, con| (row.send attr) == con }
|
|
76
|
-
end
|
|
77
|
-
|
|
78
|
-
end
|
|
79
|
-
|
|
80
|
-
#
|
|
81
|
-
# Convert to csv string
|
|
82
|
-
#
|
|
83
|
-
# options: {
|
|
84
|
-
# headers: boolean
|
|
85
|
-
# }
|
|
86
|
-
#
|
|
87
|
-
def to_csv options = {}
|
|
88
|
-
csv = ""
|
|
89
|
-
csv += CSV.generate_line(self.class.headers.map { |k, v| v } ) if options[:headers]
|
|
90
|
-
csv += @rows.map(&:to_csv).join
|
|
91
|
-
end
|
|
92
|
-
end
|
|
93
|
-
|
|
94
|
-
private
|
|
95
|
-
#
|
|
96
|
-
# Get headers that include super class's one.
|
|
97
|
-
#
|
|
98
|
-
def all_headers current_class = nil
|
|
99
|
-
current_class ||= self
|
|
100
|
-
return {} if current_class == Base
|
|
101
|
-
current_header = current_class.headers || {}
|
|
102
|
-
return current_header.merge all_headers(current_class.superclass)
|
|
103
|
-
end
|
|
104
|
-
|
|
105
|
-
#
|
|
106
|
-
# Define a class which represent a row of csv.
|
|
107
|
-
#
|
|
108
|
-
def define_row headers
|
|
109
|
-
headers ||= {}
|
|
110
|
-
|
|
111
|
-
# get the superclass for Row
|
|
112
|
-
baseclass = if superclass.const_defined? :Row
|
|
113
|
-
superclass::Row
|
|
114
|
-
else
|
|
115
|
-
Object
|
|
116
|
-
end
|
|
117
|
-
|
|
118
|
-
# remove class definition
|
|
119
|
-
if const_defined? :Row and baseclass != self::Row
|
|
120
|
-
self.send :remove_const, :Row
|
|
121
|
-
end
|
|
122
|
-
|
|
123
|
-
# define Row class
|
|
124
|
-
const_set :Row, (Class.new(baseclass) do
|
|
125
|
-
|
|
126
|
-
attr_accessor *headers.keys
|
|
127
|
-
|
|
128
|
-
define_method :initialize do |line = {}|
|
|
129
|
-
headers.each do |k, v|
|
|
130
|
-
instance_variable_set "@#{k.to_s}", line[v]
|
|
131
|
-
end
|
|
132
|
-
end
|
|
133
|
-
|
|
134
|
-
define_method :to_csv do
|
|
135
|
-
CSV.generate_line headers.map { |k, v| self.send k }
|
|
136
|
-
end
|
|
137
|
-
|
|
138
|
-
end)
|
|
139
|
-
end
|
|
5
|
+
autoload :Base, 'rcsv_loader/base'
|
|
140
6
|
end
|
data/spec/core_spec.rb
ADDED
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
require 'spec_helper'
|
|
2
|
+
require 'pathname'
|
|
3
|
+
|
|
4
|
+
require 'models/sample_csv'
|
|
5
|
+
require 'models/sample_csv_no_headers'
|
|
6
|
+
|
|
7
|
+
describe RCsvLoader do
|
|
8
|
+
|
|
9
|
+
describe RCsvLoader::Core do
|
|
10
|
+
|
|
11
|
+
shared_examples 'to_csv' do |expected|
|
|
12
|
+
subject { data.to_csv }
|
|
13
|
+
it { is_expected.to eq expected }
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
shared_examples 'to_csv without headers' do |expected|
|
|
17
|
+
subject { data.to_csv headers: false }
|
|
18
|
+
it { is_expected.to eq expected }
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
context "sample"do
|
|
22
|
+
let(:path) { File.join Pathname(__FILE__).dirname, "fixtures/sample.csv" }
|
|
23
|
+
let(:data) { SampleCsv.load_csv path, headers: true }
|
|
24
|
+
|
|
25
|
+
expected_with_headers = [
|
|
26
|
+
'id,file name,extension,url',
|
|
27
|
+
'1,file_01.zip,zip,https://example.com/file_01.zip',
|
|
28
|
+
'2,file_02.zip,zip,https://example.com/file_02.zip',
|
|
29
|
+
''
|
|
30
|
+
].join($/)
|
|
31
|
+
it_behaves_like 'to_csv', expected_with_headers
|
|
32
|
+
|
|
33
|
+
expected_without_headers = [
|
|
34
|
+
'1,file_01.zip,zip,https://example.com/file_01.zip',
|
|
35
|
+
'2,file_02.zip,zip,https://example.com/file_02.zip',
|
|
36
|
+
''
|
|
37
|
+
].join($/)
|
|
38
|
+
it_behaves_like 'to_csv without headers', expected_without_headers
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
context "sample_without_headers" do
|
|
42
|
+
let(:path) { File.join Pathname(__FILE__).dirname, "fixtures/no_headers_sample.csv" }
|
|
43
|
+
let(:data) { SampleCsvNoHeaders.load_csv path, headers: false }
|
|
44
|
+
|
|
45
|
+
expected_with_headers = [
|
|
46
|
+
'id,file_name,extension,url',
|
|
47
|
+
'1,file_01.zip,zip,https://example.com/file_01.zip',
|
|
48
|
+
'2,file_02.zip,zip,https://example.com/file_02.zip',
|
|
49
|
+
''
|
|
50
|
+
].join($/)
|
|
51
|
+
it_behaves_like 'to_csv', expected_with_headers
|
|
52
|
+
|
|
53
|
+
expected_without_headers = [
|
|
54
|
+
'1,file_01.zip,zip,https://example.com/file_01.zip',
|
|
55
|
+
'2,file_02.zip,zip,https://example.com/file_02.zip',
|
|
56
|
+
''
|
|
57
|
+
].join($/)
|
|
58
|
+
it_behaves_like 'to_csv without headers', expected_without_headers
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
end
|
data/spec/rcsv_loader_spec.rb
CHANGED
|
@@ -84,6 +84,19 @@ describe RCsvLoader do
|
|
|
84
84
|
}
|
|
85
85
|
it_behaves_like "where", expected
|
|
86
86
|
end
|
|
87
|
+
|
|
88
|
+
context ':regexp => true, :file_name => ".*?\.zip"' do
|
|
89
|
+
let(:results) { sample.where( { :file_name => ".*?\.zip" }, :regexp => true) }
|
|
90
|
+
expected = {
|
|
91
|
+
:data_count => 2,
|
|
92
|
+
:first_row => {
|
|
93
|
+
:file_name => "file_01.zip",
|
|
94
|
+
:extension => "zip",
|
|
95
|
+
:url => "https://example.com/file_01.zip"
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
it_behaves_like "where", expected
|
|
99
|
+
end
|
|
87
100
|
end
|
|
88
101
|
end
|
|
89
102
|
|
|
@@ -130,6 +143,20 @@ describe RCsvLoader do
|
|
|
130
143
|
}
|
|
131
144
|
it_behaves_like "where", expected
|
|
132
145
|
end
|
|
146
|
+
|
|
147
|
+
context ':regexp => true, :file_name => ".*?\.zip"' do
|
|
148
|
+
let(:results) { sample.where( { :file_name => ".*?\.zip" }, :regexp => true) }
|
|
149
|
+
expected = {
|
|
150
|
+
:data_count => 2,
|
|
151
|
+
:first_row => {
|
|
152
|
+
:file_name => "file_01.zip",
|
|
153
|
+
:extension => "zip",
|
|
154
|
+
:url => "https://example.com/file_01.zip"
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
it_behaves_like "where", expected
|
|
158
|
+
end
|
|
159
|
+
|
|
133
160
|
end
|
|
134
161
|
|
|
135
162
|
end
|
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: rcsv_loader
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.0
|
|
4
|
+
version: 0.2.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- osadake212
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: bin
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date: 2015-
|
|
11
|
+
date: 2015-05-02 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: bundler
|
|
@@ -67,8 +67,12 @@ files:
|
|
|
67
67
|
- README.md
|
|
68
68
|
- Rakefile
|
|
69
69
|
- lib/rcsv_loader.rb
|
|
70
|
+
- lib/rcsv_loader/base.rb
|
|
71
|
+
- lib/rcsv_loader/core.rb
|
|
70
72
|
- lib/rcsv_loader/version.rb
|
|
73
|
+
- lib/rcsv_loader/where.rb
|
|
71
74
|
- rcsv_loader.gemspec
|
|
75
|
+
- spec/core_spec.rb
|
|
72
76
|
- spec/fixtures/no_headers_sample.csv
|
|
73
77
|
- spec/fixtures/sample.csv
|
|
74
78
|
- spec/models/sample_csv.rb
|
|
@@ -100,6 +104,7 @@ signing_key:
|
|
|
100
104
|
specification_version: 4
|
|
101
105
|
summary: A simple csv loader.
|
|
102
106
|
test_files:
|
|
107
|
+
- spec/core_spec.rb
|
|
103
108
|
- spec/fixtures/no_headers_sample.csv
|
|
104
109
|
- spec/fixtures/sample.csv
|
|
105
110
|
- spec/models/sample_csv.rb
|