csv_find 0.0.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/lib/csv_find/csv_find.rb +165 -0
- data/spec/csv_find_spec.rb +103 -0
- metadata +60 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: fad9ba988bfb458d1f4cf9d27d4b3b6ff1fa97ef
|
4
|
+
data.tar.gz: e648ecab510c2f0c439ce25d8ba05ab7831b4ec6
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: ecb6a2486aa3c178e583914a02930d31b5cbd1656791fccaf2aa1536db80620129184320ab26dc979e70f012e1a60060b239e57052cb7b7154da4a7a2424fa8a
|
7
|
+
data.tar.gz: 08689bf0756703c741e416f5f5174851959300cd47849b5c1c3ecececbf891b97b5551e159392cc8a9257ef7079cdfa769e4dc2e7c4b6a3735f65d0c4a0e9c26
|
@@ -0,0 +1,165 @@
|
|
1
|
+
module CsvFind
|
2
|
+
require 'csv'
|
3
|
+
|
4
|
+
VERSION = {
|
5
|
+
major: '0',
|
6
|
+
minor: '0',
|
7
|
+
patch: '1'
|
8
|
+
}.values.join('.')
|
9
|
+
|
10
|
+
def self.included(base)
|
11
|
+
base.send :extend, ClassMethods
|
12
|
+
base.send :prepend, InstanceMethods
|
13
|
+
end
|
14
|
+
|
15
|
+
module InstanceMethods
|
16
|
+
attr_accessor :line_number
|
17
|
+
|
18
|
+
def initialize(hash = {})
|
19
|
+
hash.each { |k,v| send("#{k}=".to_sym, v) }
|
20
|
+
end
|
21
|
+
|
22
|
+
def ==(other_instance)
|
23
|
+
instance_variables.map do |instance_variable|
|
24
|
+
instance_variable_get(instance_variable) ==
|
25
|
+
other_instance.instance_variable_get(instance_variable)
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
private
|
30
|
+
|
31
|
+
attr_reader :hash
|
32
|
+
end
|
33
|
+
|
34
|
+
module ClassMethods
|
35
|
+
include Enumerable
|
36
|
+
|
37
|
+
attr_reader :headers, :file, :file_options,
|
38
|
+
:first_line, :middle_line, :last_line
|
39
|
+
|
40
|
+
def csv_file(file_name, options = {})
|
41
|
+
@file_options = default_options.merge(options)
|
42
|
+
@file = CSV.new(File.open(file_name, 'r'), @file_options)
|
43
|
+
@first_line = 2
|
44
|
+
@last_line = `wc -l #{file_name}`.split(' ').first.to_i
|
45
|
+
@middle_line = (@last_line/2) + 1
|
46
|
+
@line_number = nil
|
47
|
+
@headers = extract_headers(file_name, file_options)
|
48
|
+
|
49
|
+
define_accessors
|
50
|
+
end
|
51
|
+
|
52
|
+
def define_accessors
|
53
|
+
headers.each do |header|
|
54
|
+
send(:attr_accessor, header)
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
def all
|
59
|
+
rewind
|
60
|
+
file.map { |row| build_instance(row, file.lineno) }
|
61
|
+
end
|
62
|
+
|
63
|
+
def where(key_val_pair)
|
64
|
+
search(key_val_pair).map { |row| build_instance(row, row[:line_number]) }
|
65
|
+
end
|
66
|
+
|
67
|
+
def find_by(key_val_pair)
|
68
|
+
warn DEPRECATION_MESSAGE
|
69
|
+
row = search(key_val_pair).last
|
70
|
+
row.nil? ? nil : build_instance(row, row[:line_number])
|
71
|
+
end
|
72
|
+
|
73
|
+
def find_all_by(key_val_pair)
|
74
|
+
warn DEPRECATION_MESSAGE
|
75
|
+
where(key_val_pair)
|
76
|
+
end
|
77
|
+
|
78
|
+
def find(line_number)
|
79
|
+
row = if (first_line..middle_line).include?(line_number)
|
80
|
+
front_find(line_number, file.path)
|
81
|
+
else
|
82
|
+
back_find(line_number, file.path)
|
83
|
+
end
|
84
|
+
|
85
|
+
row.nil? ? row : build_instance(row, line_number)
|
86
|
+
end
|
87
|
+
|
88
|
+
def first
|
89
|
+
rewind
|
90
|
+
build_instance(file.first, first_line)
|
91
|
+
end
|
92
|
+
|
93
|
+
def last
|
94
|
+
command = `head -n 1 #{file.path} && tail -n 1 #{file.path}`
|
95
|
+
last_row = CSV.new(command, file_options).first
|
96
|
+
build_instance(last_row, last_line)
|
97
|
+
end
|
98
|
+
|
99
|
+
def each
|
100
|
+
rewind
|
101
|
+
(first_line..last_line).each do |line_number|
|
102
|
+
yield find(line_number) if block_given?
|
103
|
+
end
|
104
|
+
end
|
105
|
+
|
106
|
+
private
|
107
|
+
|
108
|
+
DEPRECATION_MESSAGE =
|
109
|
+
'[DEPRECATION] This method is deprecated and will be removed in v2.' <<
|
110
|
+
'Please user #where.'
|
111
|
+
|
112
|
+
def default_options
|
113
|
+
{
|
114
|
+
headers: true,
|
115
|
+
header_converters: :symbol,
|
116
|
+
return_headers: false
|
117
|
+
}
|
118
|
+
end
|
119
|
+
|
120
|
+
def extract_headers(file_name, options)
|
121
|
+
csv_file = File.open(file_name,'r')
|
122
|
+
CSV.new(csv_file, options).first.headers
|
123
|
+
end
|
124
|
+
|
125
|
+
def build_instance(row, line)
|
126
|
+
new_instance = new
|
127
|
+
row.each { |key, value| new_instance.send("#{key}=".to_sym, value) }
|
128
|
+
new_instance.line_number = line
|
129
|
+
|
130
|
+
new_instance
|
131
|
+
end
|
132
|
+
|
133
|
+
def rewind
|
134
|
+
file.rewind
|
135
|
+
end
|
136
|
+
|
137
|
+
def search(key_val_pair)
|
138
|
+
rewind
|
139
|
+
@results = file
|
140
|
+
@pairs = key_val_pair
|
141
|
+
|
142
|
+
@pairs.each { |pair| @results = dig(pair, @results) }
|
143
|
+
|
144
|
+
@results
|
145
|
+
end
|
146
|
+
|
147
|
+
def dig(hash_pair, rows)
|
148
|
+
rows.select do |row|
|
149
|
+
if row[hash_pair.first] == hash_pair.last
|
150
|
+
$. != last_line ? row.push(line_number: $.) : row
|
151
|
+
end
|
152
|
+
end
|
153
|
+
end
|
154
|
+
|
155
|
+
def front_find(line_number, file_path)
|
156
|
+
command = `head -n 1 #{file_path} && head -n #{line_number} #{file_path} | tail -n 1`
|
157
|
+
CSV.new(command, file_options).first
|
158
|
+
end
|
159
|
+
|
160
|
+
def back_find(line_number, file_path)
|
161
|
+
command = `head -n 1 #{file_path} && tail -n #{(last_line + 1) - line_number} #{file_path} | head -n 1`
|
162
|
+
CSV.new(command, file_options).first
|
163
|
+
end
|
164
|
+
end
|
165
|
+
end
|
@@ -0,0 +1,103 @@
|
|
1
|
+
require './lib/csv_find'
|
2
|
+
|
3
|
+
class People
|
4
|
+
include CsvFind
|
5
|
+
csv_file('spec/support/demo.csv', {})
|
6
|
+
end
|
7
|
+
|
8
|
+
describe People do
|
9
|
+
before(:all){
|
10
|
+
@person1 = People.new(first: 'Mark', last: 'Platt', nickname: 'JCool', line_number: 2)
|
11
|
+
@person2 = People.new(first: 'Longinus', last: 'Smith', nickname: 'Pebbles', line_number: 3)
|
12
|
+
@person3 = People.new(first: 'Johnny', last: 'Radiation', nickname: 'Pebbles', line_number: 4)
|
13
|
+
@person4 = People.new(first: 'Charlie', last: 'Mansfield', nickname: 'Sammykins', line_number: 5)
|
14
|
+
}
|
15
|
+
|
16
|
+
context 'class methods' do
|
17
|
+
it "responds to .first" do
|
18
|
+
(People).should respond_to(:first)
|
19
|
+
end
|
20
|
+
|
21
|
+
it ".first returns correctly" do
|
22
|
+
expect(People.first).to eq @person1
|
23
|
+
end
|
24
|
+
|
25
|
+
it "responds to .last" do
|
26
|
+
(People).should respond_to(:last)
|
27
|
+
end
|
28
|
+
|
29
|
+
it ".last returns correctly" do
|
30
|
+
expect(People.last).to eq @person4
|
31
|
+
end
|
32
|
+
|
33
|
+
it "responds to .find" do
|
34
|
+
(People).should respond_to(:find)
|
35
|
+
end
|
36
|
+
|
37
|
+
it ".find returns correctly" do
|
38
|
+
expect(People.find(2)).to eq @person1
|
39
|
+
expect(People.find(3)).to eq @person2
|
40
|
+
expect(People.find(4)).to eq @person3
|
41
|
+
expect(People.find(5)).to eq @person4
|
42
|
+
end
|
43
|
+
|
44
|
+
it "[DEPRECATED] responds to .find_by" do
|
45
|
+
(People).should respond_to(:find_by)
|
46
|
+
end
|
47
|
+
|
48
|
+
it "[DEPRECATED] .find_by returns correctly" do
|
49
|
+
expect(People.find_by(nickname: 'Pebbles')).to eq @person3
|
50
|
+
expect(People.find_by(nickname: 'Pebbles', last: 'Smith')).to eq @person2
|
51
|
+
end
|
52
|
+
|
53
|
+
it ".find_by returns an nil if there are no results" do
|
54
|
+
expect(People.find_by(nickname: 'Beastmode')).to eq nil
|
55
|
+
end
|
56
|
+
|
57
|
+
|
58
|
+
it "responds to .where" do
|
59
|
+
(People).should respond_to(:where)
|
60
|
+
end
|
61
|
+
|
62
|
+
it ".where returns correctly" do
|
63
|
+
expect(People.where(nickname: 'Pebbles')).to eq [@person2, @person3]
|
64
|
+
expect(People.where(nickname: 'Pebbles', last: 'Radiation')).to eq [@person3]
|
65
|
+
end
|
66
|
+
|
67
|
+
it ".where returns an empty array if there are no results" do
|
68
|
+
expect(People.where(nickname: 'Beastmode')).to eq []
|
69
|
+
end
|
70
|
+
|
71
|
+
it "[DEPRECATED] responds to .find_all_by" do
|
72
|
+
(People).should respond_to(:find_all_by)
|
73
|
+
end
|
74
|
+
|
75
|
+
it "[DEPRECATED] .find_all_by returns correctly" do
|
76
|
+
expect(People.find_all_by(nickname: 'Pebbles')).to eq [@person2, @person3]
|
77
|
+
expect(People.find_all_by(nickname: 'Pebbles', last: 'Radiation')).to eq [@person3]
|
78
|
+
end
|
79
|
+
|
80
|
+
it "responds to .each" do
|
81
|
+
(People).should respond_to(:each)
|
82
|
+
end
|
83
|
+
|
84
|
+
it ".each line yields" do
|
85
|
+
@output = []
|
86
|
+
People.each{ |person| @output << person.first }
|
87
|
+
expect(@output).to eq ['Mark', 'Longinus', 'Johnny', 'Charlie']
|
88
|
+
end
|
89
|
+
end
|
90
|
+
context 'instance methods' do
|
91
|
+
it "responds to .first as defined in the csv" do
|
92
|
+
(People.new).should respond_to(:first)
|
93
|
+
end
|
94
|
+
|
95
|
+
it "responds to .last as defined in the csv" do
|
96
|
+
(People.new).should respond_to(:last)
|
97
|
+
end
|
98
|
+
|
99
|
+
it "responds to .nickname as defined in the csv" do
|
100
|
+
(People.new).should respond_to(:nickname)
|
101
|
+
end
|
102
|
+
end
|
103
|
+
end
|
metadata
ADDED
@@ -0,0 +1,60 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: csv_find
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Mark Platt
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2015-05-22 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: rspec
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: 2.14.1
|
20
|
+
type: :development
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - "~>"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: 2.14.1
|
27
|
+
description: "'csv_find will blah blah blah'"
|
28
|
+
email: mplatt@mrkplt.com
|
29
|
+
executables: []
|
30
|
+
extensions: []
|
31
|
+
extra_rdoc_files: []
|
32
|
+
files:
|
33
|
+
- lib/csv_find/csv_find.rb
|
34
|
+
- spec/csv_find_spec.rb
|
35
|
+
homepage: http://mrkplt.com
|
36
|
+
licenses:
|
37
|
+
- MIT
|
38
|
+
metadata: {}
|
39
|
+
post_install_message:
|
40
|
+
rdoc_options: []
|
41
|
+
require_paths:
|
42
|
+
- lib
|
43
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - ">="
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: 2.0.0
|
48
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
49
|
+
requirements:
|
50
|
+
- - ">="
|
51
|
+
- !ruby/object:Gem::Version
|
52
|
+
version: '0'
|
53
|
+
requirements: []
|
54
|
+
rubyforge_project:
|
55
|
+
rubygems_version: 2.2.2
|
56
|
+
signing_key:
|
57
|
+
specification_version: 4
|
58
|
+
summary: "'blah'"
|
59
|
+
test_files:
|
60
|
+
- spec/csv_find_spec.rb
|