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.
@@ -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