csv_record 2.1.2 → 3.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.ruby-gemset +1 -0
- data/.ruby-version +1 -0
- data/.travis.yml +4 -1
- data/README.md +51 -39
- data/Rakefile +1 -1
- data/csv_record.gemspec +8 -6
- data/lib/csv_record.rb +0 -23
- data/lib/csv_record/associations.rb +1 -1
- data/lib/csv_record/callback.rb +4 -2
- data/lib/csv_record/callbacks.rb +21 -19
- data/lib/csv_record/{csv_queries/condition.rb → condition.rb} +4 -2
- data/lib/csv_record/connector.rb +9 -7
- data/lib/csv_record/csv_validations/custom_validation.rb +8 -5
- data/lib/csv_record/csv_validations/presence_validation.rb +6 -4
- data/lib/csv_record/csv_validations/uniqueness_validation.rb +8 -5
- data/lib/csv_record/csv_validations/validations.rb +23 -28
- data/lib/csv_record/document.rb +12 -12
- data/lib/csv_record/field.rb +6 -4
- data/lib/csv_record/fields.rb +45 -0
- data/lib/csv_record/helpers.rb +10 -6
- data/lib/csv_record/{csv_queries/query.rb → query.rb} +8 -15
- data/lib/csv_record/reader.rb +120 -0
- data/lib/csv_record/timestamps.rb +4 -2
- data/lib/csv_record/version.rb +3 -3
- data/lib/csv_record/writer.rb +143 -0
- data/test/csv_record/associations_test.rb +1 -1
- data/test/csv_record/connector_test.rb +3 -3
- data/test/csv_record/reader_test.rb +6 -6
- data/test/csv_record/validation_test.rb +1 -1
- data/test/models/callback_test_class.rb +1 -2
- data/test/models/custom_errors_class.rb +2 -1
- data/test/models/customized_class.rb +1 -1
- data/test/models/jedi.rb +4 -3
- data/test/models/jedi_order.rb +2 -2
- data/test/models/padawan.rb +1 -1
- data/test/test_helper.rb +3 -3
- data/test/{helpers.rb → test_helpers.rb} +2 -2
- metadata +80 -52
- data/lib/csv_record/csv_fields.rb +0 -45
- data/lib/csv_record/csv_readers/class_reader.rb +0 -82
- data/lib/csv_record/csv_readers/instance_reader.rb +0 -29
- data/lib/csv_record/csv_readers/reader.rb +0 -9
- data/lib/csv_record/csv_writers/class_writer.rb +0 -52
- data/lib/csv_record/csv_writers/instance_writer.rb +0 -86
- data/lib/csv_record/csv_writers/writer.rb +0 -9
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: b56ddc51a9bc473b810efc0342ede311cf20fc01
|
4
|
+
data.tar.gz: 26a034a21daf07b878aa68ace0668ca689a567e9
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 1f849ebfc371659527501acc487df4c0a78d001edb8deb5027c242369bce46aef9cbfd0f7c94265fa8070972d99678204a8243adf59c876545d68032f652acac
|
7
|
+
data.tar.gz: 6a934c1164d1ea2605bc4884b82efbe355b210cbb434d772c1a825a2c0a69e9f1873f91f34dd386af94cef2191867bb18bb350d16861f1b8aa9baae8b31e8ecc
|
data/.ruby-gemset
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
csv_record
|
data/.ruby-version
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
ruby-2.4.2
|
data/.travis.yml
CHANGED
data/README.md
CHANGED
@@ -1,10 +1,14 @@
|
|
1
1
|
# CsvRecord
|
2
2
|
|
3
|
-
[![Build Status](https://travis-ci.org/lukelex/csv_record.png?branch=2.0.0)](https://travis-ci.org/lukelex/csv_record)
|
3
|
+
[![Build Status](https://travis-ci.org/lukelex/csv_record.png?branch=2.0.0)](https://travis-ci.org/lukelex/csv_record)
|
4
|
+
[![Code Climate](https://codeclimate.com/badge.png)](https://codeclimate.com/github/lukelex/csv_record)
|
5
|
+
[![Gem Version](https://fury-badge.herokuapp.com/rb/csv_record.png)](http://badge.fury.io/rb/csv_record)
|
4
6
|
|
5
|
-
CSV Record connects Ruby classes to CSV documents
|
7
|
+
CSV Record connects Ruby classes to CSV documents in order to
|
8
|
+
establish an almost zero-configuration persistence layer for
|
9
|
+
applications.
|
6
10
|
|
7
|
-
##Getting Started
|
11
|
+
## Getting Started
|
8
12
|
|
9
13
|
Add this line to your application's Gemfile:
|
10
14
|
|
@@ -24,7 +28,8 @@ Or install it yourself as:
|
|
24
28
|
$ gem install csv_record
|
25
29
|
```
|
26
30
|
|
27
|
-
And inside your Ruby models just require and include the CSVRecord
|
31
|
+
And inside your Ruby models just require and include the CSVRecord
|
32
|
+
lib and start using it in the same way as your are used to:
|
28
33
|
|
29
34
|
```ruby
|
30
35
|
require 'csv_record'
|
@@ -36,27 +41,28 @@ class Jedi
|
|
36
41
|
end
|
37
42
|
```
|
38
43
|
|
39
|
-
##
|
40
|
-
To persist the data objects created in your application
|
44
|
+
## Persistence
|
45
|
+
To persist the data objects created in your application you can
|
46
|
+
use the following methods:
|
41
47
|
|
42
48
|
```ruby
|
43
|
-
Jedi.create( # save the new record in
|
49
|
+
Jedi.create( # save the new record in its CSV file
|
44
50
|
name: 'Luke Skywalker',
|
45
51
|
age: 18,
|
46
52
|
midi_chlorians: '12k'
|
47
53
|
)
|
48
54
|
|
49
|
-
jedi.save # save the record in
|
55
|
+
jedi.save # save the record in its CSV file (either creating or changing)
|
50
56
|
|
51
57
|
jedi.update_attribute :age, 29 # update a single field of an object
|
52
58
|
jedi.update_attributes age: 29, midi_chlorians: '18k' # update multiple fields at the same time
|
53
59
|
|
54
|
-
jedi.destroy # removes the record from
|
60
|
+
jedi.destroy # removes the record from its CSV file
|
55
61
|
|
56
62
|
jedi.new_record? # checks if the record is new
|
57
63
|
```
|
58
64
|
|
59
|
-
##Querying
|
65
|
+
## Querying
|
60
66
|
Records can be queried through the following methods:
|
61
67
|
|
62
68
|
```ruby
|
@@ -70,10 +76,10 @@ Jedi.find_by_name_and_age 'Luke Skywalker', 18 # find dynamically with multiple
|
|
70
76
|
|
71
77
|
Jedi.where age: 18, name: 'Luke Skywalker', midi_chlorians: '12k' # find with a multiple parameters hash
|
72
78
|
|
73
|
-
Jedi.count # returns the amount of records in
|
79
|
+
Jedi.count # returns the amount of records in its CSV file
|
74
80
|
|
75
|
-
Jedi.first # retrieves the first record in
|
76
|
-
Jedi.last # retrieves the last record in
|
81
|
+
Jedi.first # retrieves the first record in its CSV file
|
82
|
+
Jedi.last # retrieves the last record in its CSV file
|
77
83
|
```
|
78
84
|
|
79
85
|
Lazy querying is the default behavior now Yey!!
|
@@ -85,8 +91,8 @@ query # #<CsvRecord::Query:0x007fdff3d31aa0>
|
|
85
91
|
query.first # #<Jedi:0x007f9df6cea478>
|
86
92
|
```
|
87
93
|
|
88
|
-
##Associations
|
89
|
-
###Belongs To
|
94
|
+
## Associations
|
95
|
+
### Belongs To
|
90
96
|
A Belongs To association can be declared through the following method:
|
91
97
|
|
92
98
|
```ruby
|
@@ -117,7 +123,7 @@ jedi.save
|
|
117
123
|
jedi.jedi_order # #<JediOrder:0x007f9b249b24d8>
|
118
124
|
```
|
119
125
|
|
120
|
-
###Has Many
|
126
|
+
### Has Many
|
121
127
|
Extending the previous example, you can use the `has_many` method to establish the inverse relationship:
|
122
128
|
|
123
129
|
```ruby
|
@@ -137,7 +143,7 @@ jedi.save
|
|
137
143
|
jedi_order.jedis # [#<Jedi:0x007f9b249b24d8>]
|
138
144
|
```
|
139
145
|
|
140
|
-
###Has One
|
146
|
+
### Has One
|
141
147
|
The same as has_many but limited to one associated record.
|
142
148
|
|
143
149
|
```ruby
|
@@ -164,11 +170,11 @@ jedi.padawan = padawan
|
|
164
170
|
jedi.padawan # #<Padawan:0x007f9b249b24d8>
|
165
171
|
```
|
166
172
|
|
167
|
-
##Callbacks
|
168
|
-
###Overview
|
173
|
+
## Callbacks
|
174
|
+
### Overview
|
169
175
|
Callbacks can be used to execute code on predetermined moments.
|
170
176
|
|
171
|
-
####Usage
|
177
|
+
#### Usage
|
172
178
|
```ruby
|
173
179
|
after_create do
|
174
180
|
# learn the way of the force
|
@@ -176,14 +182,14 @@ end
|
|
176
182
|
```
|
177
183
|
`self` refers to the instance you are in
|
178
184
|
|
179
|
-
###
|
185
|
+
### Available Callbacks
|
180
186
|
Here is a list with all the available callbacks, listed in the same order in which they will get called during the respective operations:
|
181
187
|
|
182
|
-
####Finding an Object
|
188
|
+
#### Finding an Object
|
183
189
|
* after_initialize
|
184
190
|
* after_find
|
185
191
|
|
186
|
-
####Creating an Object
|
192
|
+
#### Creating an Object
|
187
193
|
* after_initialize
|
188
194
|
* before_validation
|
189
195
|
* after_validation
|
@@ -192,7 +198,7 @@ Here is a list with all the available callbacks, listed in the same order in whi
|
|
192
198
|
* after_create
|
193
199
|
* after_save
|
194
200
|
|
195
|
-
####Updating an Object
|
201
|
+
#### Updating an Object
|
196
202
|
* before_validation
|
197
203
|
* after_validation
|
198
204
|
* before_save
|
@@ -200,16 +206,16 @@ Here is a list with all the available callbacks, listed in the same order in whi
|
|
200
206
|
* after_update
|
201
207
|
* after_save
|
202
208
|
|
203
|
-
####Destroying an Object
|
209
|
+
#### Destroying an Object
|
204
210
|
* before_destroy
|
205
211
|
* after_destroy
|
206
212
|
|
207
|
-
##Validations
|
208
|
-
###Helpers available:
|
213
|
+
## Validations
|
214
|
+
### Helpers available:
|
209
215
|
|
210
216
|
`validates_presence_of`: Ensures if the specified attribute(s) were filled
|
211
217
|
|
212
|
-
`validates_uniqueness_of`: Ensures that the specified attribute(s) are unique within
|
218
|
+
`validates_uniqueness_of`: Ensures that the specified attribute(s) are unique within its CSV file
|
213
219
|
|
214
220
|
`validate`: Uses custom method(s) to validate the model
|
215
221
|
|
@@ -240,30 +246,36 @@ jedi.invalid? # => true
|
|
240
246
|
jedi.save # => false
|
241
247
|
```
|
242
248
|
|
243
|
-
##Customizations
|
249
|
+
## Customizations
|
244
250
|
|
245
|
-
Someday you might want to go "out of the rail" that we propose.
|
251
|
+
Someday you might want to go "out of the rail" that we propose.
|
252
|
+
Here is what you can do now:
|
246
253
|
|
247
|
-
###Changing the table_name
|
254
|
+
### Changing the table_name
|
248
255
|
```ruby
|
249
256
|
store_as :wierd_table_name
|
250
257
|
```
|
251
|
-
###Changing the field column name
|
258
|
+
### Changing the field column name
|
252
259
|
```ruby
|
253
260
|
mapping :name => :wierd_field
|
254
261
|
```
|
255
262
|
|
256
|
-
##Bug reports
|
263
|
+
## Bug reports
|
257
264
|
|
258
|
-
If you discover a problem with CSV_Record, we would like to know
|
265
|
+
If you discover a problem with CSV_Record, we would like to know
|
266
|
+
about it. Please let us know on the project issues page.
|
259
267
|
|
260
|
-
##Contributing
|
268
|
+
## Contributing
|
261
269
|
|
262
|
-
We hope that you will consider contributing to CSV_Record. Please
|
270
|
+
We hope that you will consider contributing to CSV_Record. Please
|
271
|
+
read this short overview for some information about how to get started:
|
263
272
|
|
264
273
|
https://github.com/lukelex/csv_record/wiki/Contributing
|
265
274
|
|
266
|
-
You will usually want to write tests for your changes. To run the
|
275
|
+
You will usually want to write tests for your changes. To run the
|
276
|
+
test suite, go into CSV_Record's top-level directory and run
|
277
|
+
"bundle install" and "rake". For the tests to pass.
|
267
278
|
|
268
|
-
##Precautions
|
269
|
-
CsvRecord creates a `db` folder in the root of your application.
|
279
|
+
## Precautions
|
280
|
+
CsvRecord creates a `db` folder in the root of your application.
|
281
|
+
Be sure that it has permission to do so.
|
data/Rakefile
CHANGED
data/csv_record.gemspec
CHANGED
@@ -1,4 +1,3 @@
|
|
1
|
-
# -*- encoding: utf-8 -*-
|
2
1
|
require File.expand_path('../lib/csv_record/version', __FILE__)
|
3
2
|
|
4
3
|
Gem::Specification.new do |gem|
|
@@ -17,10 +16,13 @@ Gem::Specification.new do |gem|
|
|
17
16
|
gem.require_paths = ["lib"]
|
18
17
|
gem.version = CsvRecord::VERSION
|
19
18
|
|
20
|
-
gem.add_dependency 'activesupport', '~>
|
19
|
+
gem.add_dependency 'activesupport', '~> 0'
|
21
20
|
|
22
|
-
gem.add_development_dependency 'rake', '~> 0
|
23
|
-
gem.add_development_dependency 'timecop', '~> 0
|
24
|
-
gem.add_development_dependency 'turn', '~> 0
|
25
|
-
gem.add_development_dependency 'minitest', '~>
|
21
|
+
gem.add_development_dependency 'rake', '~> 0'
|
22
|
+
gem.add_development_dependency 'timecop', '~> 0'
|
23
|
+
gem.add_development_dependency 'turn', '~> 0'
|
24
|
+
gem.add_development_dependency 'minitest', '~> 0'
|
25
|
+
gem.add_development_dependency 'pry', '~> 0'
|
26
|
+
gem.add_development_dependency 'pry-nav', '~> 0'
|
27
|
+
gem.add_development_dependency 'm', '~> 0'
|
26
28
|
end
|
data/lib/csv_record.rb
CHANGED
@@ -1,26 +1,3 @@
|
|
1
|
-
#--
|
2
|
-
# Copyright (c) 2012 Lukas Alexandre
|
3
|
-
#
|
4
|
-
# Permission is hereby granted, free of charge, to any person obtaining
|
5
|
-
# a copy of this software and associated documentation files (the
|
6
|
-
# "Software"), to deal in the Software without restriction, including
|
7
|
-
# without limitation the rights to use, copy, modify, merge, publish,
|
8
|
-
# distribute, sublicense, and/or sell copies of the Software, and to
|
9
|
-
# permit persons to whom the Software is furnished to do so, subject to
|
10
|
-
# the following conditions:
|
11
|
-
#
|
12
|
-
# The above copyright notice and this permission notice shall be
|
13
|
-
# included in all copies or substantial portions of the Software.
|
14
|
-
#
|
15
|
-
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
16
|
-
# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
17
|
-
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
18
|
-
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
19
|
-
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
20
|
-
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
21
|
-
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
22
|
-
#++
|
23
|
-
|
24
1
|
require 'csv'
|
25
2
|
|
26
3
|
require 'csv_record/version'
|
data/lib/csv_record/callback.rb
CHANGED
data/lib/csv_record/callbacks.rb
CHANGED
@@ -1,4 +1,6 @@
|
|
1
|
-
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative 'callback'
|
2
4
|
|
3
5
|
module CsvRecord::Callbacks
|
4
6
|
CALLBACK_TYPES = [
|
@@ -22,7 +24,7 @@ module CsvRecord::Callbacks
|
|
22
24
|
const_variable = "#{callback_type}_callbacks".upcase
|
23
25
|
const_set(const_variable, []) unless const_defined? const_variable
|
24
26
|
if block
|
25
|
-
const_get(const_variable) <<
|
27
|
+
const_get(const_variable) << CsvRecord::Callback.new(callback_type, block)
|
26
28
|
end
|
27
29
|
end
|
28
30
|
end
|
@@ -35,9 +37,9 @@ module CsvRecord::Callbacks
|
|
35
37
|
end
|
36
38
|
|
37
39
|
module InstanceMethods
|
38
|
-
CALLBACK_TYPES.each do |
|
39
|
-
define_method "run_#{
|
40
|
-
const_variable = "#{
|
40
|
+
CALLBACK_TYPES.each do |type|
|
41
|
+
define_method "run_#{type}_callbacks" do
|
42
|
+
const_variable = "#{type}_callbacks".upcase
|
41
43
|
if self.class.const_defined? const_variable
|
42
44
|
callbacks_collection = self.class.const_get const_variable
|
43
45
|
callbacks_collection.each do |callback|
|
@@ -49,45 +51,45 @@ module CsvRecord::Callbacks
|
|
49
51
|
|
50
52
|
[:build, :initialize].each do |initialize_method|
|
51
53
|
define_method initialize_method do |*args|
|
52
|
-
result = super
|
53
|
-
|
54
|
+
result = super(*args)
|
55
|
+
run_after_initialize_callbacks
|
54
56
|
result
|
55
57
|
end
|
56
58
|
end
|
57
59
|
|
58
60
|
def valid?
|
59
|
-
|
61
|
+
run_before_validation_callbacks
|
60
62
|
is_valid = super
|
61
|
-
|
63
|
+
run_after_validation_callbacks if is_valid
|
62
64
|
is_valid
|
63
65
|
end
|
64
66
|
|
65
67
|
def destroy
|
66
|
-
|
68
|
+
run_before_destroy_callbacks
|
67
69
|
is_destroyed = super
|
68
|
-
|
70
|
+
run_after_destroy_callbacks if is_destroyed
|
69
71
|
is_destroyed
|
70
72
|
end
|
71
73
|
|
72
74
|
def save(*args)
|
73
|
-
|
75
|
+
run_before_save_callbacks
|
74
76
|
is_saved = super
|
75
|
-
|
77
|
+
run_after_save_callbacks if is_saved
|
76
78
|
is_saved
|
77
79
|
end
|
78
80
|
|
79
81
|
def append_registry
|
80
|
-
|
82
|
+
run_before_create_callbacks
|
81
83
|
is_saved = super
|
82
|
-
|
84
|
+
run_after_create_callbacks if is_saved
|
83
85
|
is_saved
|
84
86
|
end
|
85
87
|
|
86
88
|
def update_registry
|
87
|
-
|
89
|
+
run_before_update_callbacks
|
88
90
|
saved = super
|
89
|
-
|
90
|
-
|
91
|
+
run_after_destroy_callbacks if saved
|
92
|
+
run_after_update_callbacks if saved
|
91
93
|
saved
|
92
94
|
end
|
93
95
|
end
|
@@ -96,4 +98,4 @@ module CsvRecord::Callbacks
|
|
96
98
|
receiver.extend ClassMethods
|
97
99
|
receiver.send :include, InstanceMethods
|
98
100
|
end
|
99
|
-
end
|
101
|
+
end
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
class CsvRecord::Condition
|
2
4
|
attr_reader :field, :value
|
3
5
|
|
@@ -8,11 +10,11 @@ class CsvRecord::Condition
|
|
8
10
|
|
9
11
|
def self.create_from_hashes(hashes)
|
10
12
|
hashes.map do |hash|
|
11
|
-
new
|
13
|
+
new(*hash)
|
12
14
|
end
|
13
15
|
end
|
14
16
|
|
15
17
|
def to_code
|
16
18
|
"attributes['#{@field}'] == '#{@value}'"
|
17
19
|
end
|
18
|
-
end
|
20
|
+
end
|
data/lib/csv_record/connector.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module CsvRecord::Connector
|
2
4
|
DATABASE_FOLDER = 'db'.freeze
|
3
5
|
APPEND_MODE = 'a'.freeze
|
@@ -6,7 +8,7 @@ module CsvRecord::Connector
|
|
6
8
|
|
7
9
|
# Checks wheter the database directory exists
|
8
10
|
def __initialize_db_directory__
|
9
|
-
unless Dir.
|
11
|
+
unless Dir.exist?(DATABASE_FOLDER)
|
10
12
|
Dir.mkdir DATABASE_FOLDER
|
11
13
|
end
|
12
14
|
end
|
@@ -15,7 +17,7 @@ module CsvRecord::Connector
|
|
15
17
|
def __initialize_db__
|
16
18
|
__initialize_db_directory__
|
17
19
|
unless db_initialized?
|
18
|
-
open_database_file
|
20
|
+
open_database_file(WRITE_MODE) do |csv|
|
19
21
|
csv << doppelganger_fields
|
20
22
|
end
|
21
23
|
end
|
@@ -23,7 +25,7 @@ module CsvRecord::Connector
|
|
23
25
|
|
24
26
|
# Checks wheter the database file exists
|
25
27
|
def db_initialized?
|
26
|
-
File.exist? self.const_get
|
28
|
+
File.exist? self.const_get('DATABASE_LOCATION')
|
27
29
|
end
|
28
30
|
|
29
31
|
# Open the database file
|
@@ -43,7 +45,7 @@ module CsvRecord::Connector
|
|
43
45
|
CSV.open(self.const_get('DATABASE_LOCATION_TMP'), WRITE_MODE, headers: true) do |copy|
|
44
46
|
copy << fields
|
45
47
|
csv.entries.each do |entry|
|
46
|
-
new_row = yield
|
48
|
+
new_row = yield(entry)
|
47
49
|
copy << new_row if new_row
|
48
50
|
end
|
49
51
|
end
|
@@ -51,13 +53,13 @@ module CsvRecord::Connector
|
|
51
53
|
rename_database
|
52
54
|
end
|
53
55
|
|
54
|
-
|
56
|
+
private
|
55
57
|
|
56
58
|
# Rename the TMP database file to replace the original
|
57
59
|
def rename_database
|
58
60
|
old_file = self.const_get 'DATABASE_LOCATION'
|
59
61
|
tmp_file = self.const_get 'DATABASE_LOCATION_TMP'
|
60
|
-
while not File.
|
62
|
+
while not File.exist?(old_file) ; sleep(10) ; end
|
61
63
|
File.delete old_file
|
62
64
|
File.rename tmp_file, old_file
|
63
65
|
end
|
@@ -66,4 +68,4 @@ module CsvRecord::Connector
|
|
66
68
|
alias :initialize_db :__initialize_db__
|
67
69
|
alias :open_database_file :__open_database_file__
|
68
70
|
alias :parse_database_file :__parse_database_file__
|
69
|
-
end
|
71
|
+
end
|