csv_record 1.6.0 → 1.7.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.
- data/README.md +40 -12
- data/lib/csv_record/callbacks.rb +4 -3
- data/lib/csv_record/connector.rb +12 -6
- data/lib/csv_record/reader.rb +8 -0
- data/lib/csv_record/validations.rb +42 -9
- data/lib/csv_record/version.rb +1 -1
- data/lib/csv_record/writer.rb +7 -4
- data/test/csv_record/callbacks_test.rb +10 -0
- data/test/csv_record/reader_test.rb +45 -1
- data/test/csv_record/validation_test.rb +33 -0
- data/test/models/callback_test_class.rb +9 -0
- data/test/models/car.rb +0 -2
- data/test/models/jedi.rb +15 -3
- data/test/models/jedi_order.rb +2 -4
- metadata +2 -2
data/README.md
CHANGED
@@ -33,13 +33,10 @@ class Car
|
|
33
33
|
include CsvRecord::Document
|
34
34
|
|
35
35
|
attr_accessor :year, :make, :model, :description, :price
|
36
|
-
|
37
|
-
validates_presence_of :price, :model
|
38
36
|
end
|
39
37
|
```
|
40
38
|
|
41
|
-
|
42
|
-
|
39
|
+
##Persistance
|
43
40
|
```ruby
|
44
41
|
Car.create( # save the new record in the database
|
45
42
|
year: 2007,
|
@@ -50,14 +47,19 @@ Car.create( # save the new record in the database
|
|
50
47
|
)
|
51
48
|
|
52
49
|
car.save # save the record in the database (either creating or changing)
|
53
|
-
|
50
|
+
|
54
51
|
car.update_attribute :year, 1999 # update a single field of an object
|
55
52
|
car.update_attributes year: 1999, model: 'E762' # update multiple fields at the same time
|
56
53
|
|
57
54
|
car.destroy # removes the record from the database
|
58
55
|
|
59
56
|
car.new_record? # checks if the record is new
|
57
|
+
```
|
58
|
+
|
59
|
+
##Retrieving
|
60
|
+
Records can be queried through the following methds:
|
60
61
|
|
62
|
+
```ruby
|
61
63
|
Car.all # retrieves all saved records
|
62
64
|
|
63
65
|
Car.find car.id # find through its id
|
@@ -77,6 +79,7 @@ Car.last # retrieves the last record in the database
|
|
77
79
|
##Associations
|
78
80
|
###Belongs To
|
79
81
|
A Belongs To association can be declared through the following method:
|
82
|
+
|
80
83
|
```ruby
|
81
84
|
class Company
|
82
85
|
include CsvRecord::Document
|
@@ -105,6 +108,7 @@ car.company # #<Company:0x007f9b249b24d8>
|
|
105
108
|
|
106
109
|
###Has Many
|
107
110
|
Extending the previous example, you can use the `has_many` method to establish the inverse relationship:
|
111
|
+
|
108
112
|
```ruby
|
109
113
|
class Company
|
110
114
|
include CsvRecord::Document
|
@@ -123,37 +127,61 @@ company.cars # [#<Car:0x007f9b249b24d8>]
|
|
123
127
|
```
|
124
128
|
|
125
129
|
##Callbacks
|
130
|
+
###Overview
|
126
131
|
Callbacks can be used to execute code on predetermined moments.
|
127
132
|
|
133
|
+
####Usage
|
128
134
|
```ruby
|
129
|
-
before_create do |obj|
|
130
|
-
obj.do_something
|
131
|
-
end
|
132
|
-
|
133
135
|
after_create do |obj|
|
134
136
|
obj.do_something
|
135
137
|
end
|
136
138
|
```
|
137
139
|
`obj` refers to the instance you are in
|
138
140
|
|
141
|
+
###Avaiable Callbacks
|
142
|
+
Here is a list with all the available callbacks, listed in the same order in which they will get called during the respective operations:
|
143
|
+
|
144
|
+
####Creating an Object
|
145
|
+
* before_create
|
146
|
+
* before_validation
|
147
|
+
* after_validation
|
148
|
+
* after_create
|
149
|
+
|
150
|
+
####Updating an Object
|
151
|
+
* before_validation
|
152
|
+
* after_validation
|
153
|
+
|
139
154
|
##Validations
|
140
155
|
|
141
156
|
Helpers available:
|
142
157
|
|
143
158
|
`validates_presence_of`: Ensures if the specified attributes were filled
|
144
159
|
|
160
|
+
`validates_uniqueness_of`: Ensures that the specified attribute(s) are unique within the database
|
161
|
+
|
162
|
+
`validate`: Uses custom methods to validate the model
|
163
|
+
|
145
164
|
```ruby
|
146
165
|
class Company
|
147
166
|
include CsvRecord::Document
|
148
|
-
|
167
|
+
|
149
168
|
attr_accessor :name
|
169
|
+
|
170
|
+
validates_presence_of :name
|
171
|
+
validates_uniqueness_of :name
|
172
|
+
|
173
|
+
validate :my_custom_validator_method
|
174
|
+
|
175
|
+
def my_custom_validator_method
|
176
|
+
@errors = self.errors.add attribute
|
177
|
+
end
|
150
178
|
end
|
151
179
|
|
152
|
-
company = Company.create
|
180
|
+
company = Company.create
|
153
181
|
company.save
|
154
182
|
# => false
|
155
183
|
|
156
|
-
company = Company.create
|
184
|
+
company = Company.create
|
157
185
|
company.valid?
|
158
186
|
# => false
|
159
187
|
company.invalid?
|
data/lib/csv_record/callbacks.rb
CHANGED
@@ -1,12 +1,13 @@
|
|
1
1
|
module CsvRecord
|
2
2
|
module Callbacks
|
3
|
-
|
4
3
|
CALLBACKS = [
|
5
|
-
:after_create,
|
6
4
|
:after_initialize,
|
7
|
-
:
|
5
|
+
:before_validation,
|
6
|
+
:after_validation,
|
8
7
|
:before_create,
|
9
8
|
:before_save,
|
9
|
+
:after_create,
|
10
|
+
:after_save
|
10
11
|
].freeze
|
11
12
|
|
12
13
|
module ClassMethods
|
data/lib/csv_record/connector.rb
CHANGED
@@ -1,15 +1,20 @@
|
|
1
1
|
module CsvRecord
|
2
2
|
module Connector
|
3
|
+
DATABASE_FOLDER = 'db'.freeze
|
4
|
+
APPEND_MODE = 'a'.freeze
|
5
|
+
WRITE_MODE = 'wb'.freeze
|
6
|
+
READ_MODE = 'r'.freeze
|
7
|
+
|
3
8
|
def __initialize_db_directory__
|
4
|
-
unless Dir.exists?
|
5
|
-
Dir.mkdir
|
9
|
+
unless Dir.exists? DATABASE_FOLDER
|
10
|
+
Dir.mkdir DATABASE_FOLDER
|
6
11
|
end
|
7
12
|
end
|
8
13
|
|
9
14
|
def __initialize_db__
|
10
|
-
|
15
|
+
__initialize_db_directory__
|
11
16
|
unless db_initialized?
|
12
|
-
open_database_file
|
17
|
+
open_database_file WRITE_MODE do |csv|
|
13
18
|
csv << fields
|
14
19
|
end
|
15
20
|
end
|
@@ -19,7 +24,8 @@ module CsvRecord
|
|
19
24
|
File.exist? self.const_get('DATABASE_LOCATION')
|
20
25
|
end
|
21
26
|
|
22
|
-
def __open_database_file__(mode=
|
27
|
+
def __open_database_file__(mode=READ_MODE)
|
28
|
+
__initialize_db__ if mode == READ_MODE # fix this later
|
23
29
|
CSV.open(self.const_get('DATABASE_LOCATION'), mode, headers: true) do |csv|
|
24
30
|
yield(csv)
|
25
31
|
end
|
@@ -27,7 +33,7 @@ module CsvRecord
|
|
27
33
|
|
28
34
|
def __parse_database_file__
|
29
35
|
open_database_file do |csv|
|
30
|
-
CSV.open(self.const_get('DATABASE_LOCATION_TMP'),
|
36
|
+
CSV.open(self.const_get('DATABASE_LOCATION_TMP'), WRITE_MODE, headers: true) do |copy|
|
31
37
|
copy << fields
|
32
38
|
csv.entries.each do |entry|
|
33
39
|
new_row = yield(entry)
|
data/lib/csv_record/reader.rb
CHANGED
@@ -105,6 +105,14 @@ module CsvRecord
|
|
105
105
|
self.id
|
106
106
|
end
|
107
107
|
|
108
|
+
def ==(obj)
|
109
|
+
self.class == obj.class && self.to_param == obj.to_param
|
110
|
+
end
|
111
|
+
|
112
|
+
def !=(obj)
|
113
|
+
self.class != obj.class || self.to_param != obj.to_param
|
114
|
+
end
|
115
|
+
|
108
116
|
alias :attributes :__attributes__
|
109
117
|
alias :values :__values__
|
110
118
|
alias :to_param :__to_param__
|
@@ -1,22 +1,34 @@
|
|
1
1
|
module CsvRecord
|
2
2
|
module Validations
|
3
3
|
module ClassMethods
|
4
|
-
|
4
|
+
[:presence, :uniqueness].each do |kind|
|
5
|
+
define_method "fields_to_validate_#{kind}" do
|
6
|
+
eval "@fields_to_validate_#{kind} || []"
|
7
|
+
end
|
8
|
+
|
9
|
+
define_method "__validates_#{kind}_of__" do |*attr_names|
|
10
|
+
eval "@fields_to_validate_#{kind} = attr_names"
|
11
|
+
end
|
5
12
|
|
6
|
-
|
7
|
-
@fields_to_validate || []
|
13
|
+
eval "alias :validates_#{kind}_of :__validates_#{kind}_of__"
|
8
14
|
end
|
9
15
|
|
10
|
-
def
|
11
|
-
@
|
16
|
+
def custom_validators
|
17
|
+
@custom_validators || []
|
12
18
|
end
|
13
19
|
|
14
|
-
|
20
|
+
def validate(*args, &block)
|
21
|
+
@custom_validators ||= []
|
22
|
+
args.each { |arg| @custom_validators << arg }
|
23
|
+
@custom_validators << block if block_given?
|
24
|
+
end
|
15
25
|
end
|
16
26
|
|
17
27
|
module InstanceMethods
|
18
28
|
def __valid__?
|
19
|
-
|
29
|
+
trigger_presence_validations
|
30
|
+
trigger_uniqueness_validations
|
31
|
+
trigger_custom_validations
|
20
32
|
errors.empty?
|
21
33
|
end
|
22
34
|
|
@@ -31,13 +43,34 @@ module CsvRecord
|
|
31
43
|
alias :valid? :__valid__?
|
32
44
|
|
33
45
|
private
|
34
|
-
def
|
35
|
-
|
46
|
+
def trigger_presence_validations
|
47
|
+
self.class.fields_to_validate_presence.each do |attribute|
|
36
48
|
if self.public_send(attribute).nil?
|
37
49
|
@errors = self.errors.add attribute
|
38
50
|
end
|
39
51
|
end
|
40
52
|
end
|
53
|
+
|
54
|
+
def trigger_uniqueness_validations
|
55
|
+
self.class.fields_to_validate_uniqueness.each do |attribute|
|
56
|
+
condition = {}
|
57
|
+
condition[attribute] = self.public_send attribute
|
58
|
+
records = self.class.__where__ condition
|
59
|
+
if records.any? { |record| record != self }
|
60
|
+
@errors = self.errors.add attribute
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
def trigger_custom_validations
|
66
|
+
self.class.custom_validators.each do |validator|
|
67
|
+
if not validator.is_a? Proc
|
68
|
+
self.send validator
|
69
|
+
else
|
70
|
+
validator.call self
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
41
74
|
end
|
42
75
|
end
|
43
76
|
end
|
data/lib/csv_record/version.rb
CHANGED
data/lib/csv_record/writer.rb
CHANGED
@@ -26,11 +26,15 @@ module CsvRecord
|
|
26
26
|
end
|
27
27
|
|
28
28
|
def __save__
|
29
|
+
result = nil
|
30
|
+
self.run_before_validation_callbacks
|
29
31
|
if self.valid?
|
30
|
-
self.new_record? ? self.append_registry : self.update_registry
|
32
|
+
result = self.new_record? ? self.append_registry : self.update_registry
|
31
33
|
else
|
32
|
-
false
|
34
|
+
result = false
|
33
35
|
end
|
36
|
+
self.run_after_validation_callbacks
|
37
|
+
result
|
34
38
|
end
|
35
39
|
|
36
40
|
def new_record?
|
@@ -66,7 +70,6 @@ module CsvRecord
|
|
66
70
|
end
|
67
71
|
|
68
72
|
def append_registry
|
69
|
-
self.class.initialize_db
|
70
73
|
set_created_at
|
71
74
|
write_object
|
72
75
|
end
|
@@ -83,7 +86,7 @@ module CsvRecord
|
|
83
86
|
|
84
87
|
def __write_object__
|
85
88
|
calculate_id
|
86
|
-
self.class.open_database_file
|
89
|
+
self.class.open_database_file CsvRecord::Connector::APPEND_MODE do |csv|
|
87
90
|
csv << values
|
88
91
|
end
|
89
92
|
true
|
@@ -19,6 +19,8 @@ describe CsvRecord::Callbacks do
|
|
19
19
|
|
20
20
|
it ('run before_create callbacks') { klass.must_respond_to(:run_before_create_callbacks) }
|
21
21
|
it ('run after_create callbacks') { klass.must_respond_to(:run_after_create_callbacks) }
|
22
|
+
it ('run before_validation callbacks') { klass.must_respond_to(:run_before_validation_callbacks) }
|
23
|
+
it ('run after_validation callbacks') { klass.must_respond_to(:run_after_validation_callbacks) }
|
22
24
|
it ('run before_save callbacks') { klass.must_respond_to(:run_before_save_callbacks) }
|
23
25
|
it ('run after_save callbacks') { klass.must_respond_to(:run_after_save_callbacks) }
|
24
26
|
it ('run after_initialize callbacks') { klass.must_respond_to(:run_after_initialize_callbacks) }
|
@@ -34,5 +36,13 @@ describe CsvRecord::Callbacks do
|
|
34
36
|
it 'after_create' do
|
35
37
|
object_created.after_create_called.must_equal true
|
36
38
|
end
|
39
|
+
|
40
|
+
it 'before_validation' do
|
41
|
+
object_created.before_validation_called.must_equal true
|
42
|
+
end
|
43
|
+
|
44
|
+
it 'after_validation' do
|
45
|
+
object_created.after_create_called.must_equal true
|
46
|
+
end
|
37
47
|
end
|
38
48
|
end
|
@@ -1,6 +1,7 @@
|
|
1
1
|
require_relative '../test_helper'
|
2
2
|
|
3
3
|
require_relative '../models/car'
|
4
|
+
require_relative '../models/jedi'
|
4
5
|
|
5
6
|
describe CsvRecord::Reader do
|
6
7
|
describe 'initializing class methods' do
|
@@ -11,6 +12,9 @@ describe CsvRecord::Reader do
|
|
11
12
|
describe 'initializing instance methods' do
|
12
13
|
it ('responds to values') { Car.new.must_respond_to :values }
|
13
14
|
it ('responds to attributes') { Car.new.must_respond_to :attributes }
|
15
|
+
it ('responds to to_param') { Car.new.must_respond_to :to_param }
|
16
|
+
it ('responds to ==') { Car.new.must_respond_to :== }
|
17
|
+
it ('responds to !=') { Car.new.must_respond_to :!= }
|
14
18
|
end
|
15
19
|
|
16
20
|
describe 'validating the methods behavior' do
|
@@ -56,7 +60,7 @@ describe CsvRecord::Reader do
|
|
56
60
|
Car.all.size.must_equal 2
|
57
61
|
end
|
58
62
|
|
59
|
-
it "
|
63
|
+
it "counting the registries" do
|
60
64
|
car.save
|
61
65
|
Car.count.must_equal 1
|
62
66
|
second_car.save
|
@@ -70,6 +74,46 @@ describe CsvRecord::Reader do
|
|
70
74
|
car.to_param.must_equal 1
|
71
75
|
end
|
72
76
|
|
77
|
+
describe '==' do
|
78
|
+
before do
|
79
|
+
yoda.save
|
80
|
+
luke.save
|
81
|
+
jedi_council.save
|
82
|
+
end
|
83
|
+
|
84
|
+
it 'comparing with the same registry' do
|
85
|
+
(yoda == yoda).must_equal true
|
86
|
+
end
|
87
|
+
|
88
|
+
it 'comparing with a diferent registry' do
|
89
|
+
(yoda == luke).must_equal false
|
90
|
+
end
|
91
|
+
|
92
|
+
it 'comparing with another class registry' do
|
93
|
+
(yoda == jedi_council).must_equal false
|
94
|
+
end
|
95
|
+
end
|
96
|
+
|
97
|
+
describe '!=' do
|
98
|
+
before do
|
99
|
+
yoda.save
|
100
|
+
luke.save
|
101
|
+
jedi_council.save
|
102
|
+
end
|
103
|
+
|
104
|
+
it 'comparing with the same registry' do
|
105
|
+
(yoda != yoda).must_equal false
|
106
|
+
end
|
107
|
+
|
108
|
+
it 'comparing with a diferent registry' do
|
109
|
+
(yoda != luke).must_equal true
|
110
|
+
end
|
111
|
+
|
112
|
+
it 'comparing with another class registry' do
|
113
|
+
(yoda != jedi_council).must_equal true
|
114
|
+
end
|
115
|
+
end
|
116
|
+
|
73
117
|
describe 'simple query' do
|
74
118
|
let (:cars) { [] }
|
75
119
|
|
@@ -6,6 +6,7 @@ require_relative '../models/jedi_order'
|
|
6
6
|
describe CsvRecord::Validations do
|
7
7
|
describe 'initializing class methods' do
|
8
8
|
it ('responds to validates_presence_of') { Jedi.must_respond_to :validates_presence_of }
|
9
|
+
it ('responds to validates_uniqueness_of') { Jedi.must_respond_to :validates_uniqueness_of }
|
9
10
|
it ('responds to valid?') { Jedi.new.must_respond_to :valid? }
|
10
11
|
it ('responds to invalid?') { Jedi.new.must_respond_to :invalid? }
|
11
12
|
end
|
@@ -72,6 +73,38 @@ describe CsvRecord::Validations do
|
|
72
73
|
invalid_jedi.valid?
|
73
74
|
invalid_jedi.errors.length.must_equal 2
|
74
75
|
end
|
76
|
+
|
77
|
+
it 'should contain the errors found' do
|
78
|
+
invalid_jedi.valid?
|
79
|
+
invalid_jedi.errors.must_include :name
|
80
|
+
invalid_jedi.errors.must_include :age
|
81
|
+
end
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
describe 'validates_uniqueness_of' do
|
86
|
+
before { yoda.save }
|
87
|
+
|
88
|
+
let :fake_yoda do
|
89
|
+
fake_yoda = Jedi.new name: 'Yoda the green', age: 238, midi_chlorians: '1k'
|
90
|
+
end
|
91
|
+
|
92
|
+
it 'can`t have the same name' do
|
93
|
+
fake_yoda.valid?.must_equal false
|
94
|
+
end
|
95
|
+
end
|
96
|
+
|
97
|
+
describe 'custom_validator' do
|
98
|
+
it ('responds to validate') { Jedi.must_respond_to :validate }
|
99
|
+
|
100
|
+
before { yoda.valid? }
|
101
|
+
|
102
|
+
it 'adding a custom validator' do
|
103
|
+
yoda.custom_validator_checker.must_equal true
|
104
|
+
end
|
105
|
+
|
106
|
+
it 'validate can have a block' do
|
107
|
+
yoda.custom_validator_checker_with_block.must_equal true
|
75
108
|
end
|
76
109
|
end
|
77
110
|
end
|
@@ -5,11 +5,20 @@ class CallbackTestClass
|
|
5
5
|
end
|
6
6
|
|
7
7
|
attr_accessor :before_create_called, :after_create_called
|
8
|
+
attr_accessor :before_validation_called, :after_validation_called
|
8
9
|
|
9
10
|
before_create do |obj|
|
10
11
|
obj.before_create_called = true
|
11
12
|
end
|
12
13
|
|
14
|
+
before_validation do |obj|
|
15
|
+
obj.before_validation_called = true
|
16
|
+
end
|
17
|
+
|
18
|
+
after_validation do |obj|
|
19
|
+
obj.after_validation_called = true
|
20
|
+
end
|
21
|
+
|
13
22
|
after_create do |obj|
|
14
23
|
obj.after_create_called = true
|
15
24
|
end
|
data/test/models/car.rb
CHANGED
data/test/models/jedi.rb
CHANGED
@@ -1,11 +1,20 @@
|
|
1
|
-
require 'csv_record'
|
2
|
-
|
3
1
|
class Jedi
|
4
2
|
include CsvRecord::Document
|
5
3
|
|
4
|
+
attr_accessor :name, :age, :midi_chlorians
|
5
|
+
attr_reader :custom_validator_checker, :custom_validator_checker_with_block
|
6
|
+
|
6
7
|
belongs_to :jedi_order
|
7
8
|
|
8
9
|
validates_presence_of :name, :age
|
10
|
+
validates_uniqueness_of :name
|
11
|
+
|
12
|
+
validate :my_custom_validator_method
|
13
|
+
validate do |obj|
|
14
|
+
obj.instance_eval do
|
15
|
+
@custom_validator_checker_with_block = true
|
16
|
+
end
|
17
|
+
end
|
9
18
|
|
10
19
|
def initialize(params={})
|
11
20
|
params.each do |key, value|
|
@@ -13,5 +22,8 @@ class Jedi
|
|
13
22
|
end
|
14
23
|
end
|
15
24
|
|
16
|
-
|
25
|
+
private
|
26
|
+
def my_custom_validator_method
|
27
|
+
@custom_validator_checker = true
|
28
|
+
end
|
17
29
|
end
|
data/test/models/jedi_order.rb
CHANGED
@@ -1,8 +1,8 @@
|
|
1
|
-
require 'csv_record'
|
2
|
-
|
3
1
|
class JediOrder
|
4
2
|
include CsvRecord::Document
|
5
3
|
|
4
|
+
attr_accessor :rank
|
5
|
+
|
6
6
|
has_many :jedis
|
7
7
|
|
8
8
|
def initialize(params={})
|
@@ -10,6 +10,4 @@ class JediOrder
|
|
10
10
|
self.public_send("#{key}=", value)
|
11
11
|
end
|
12
12
|
end
|
13
|
-
|
14
|
-
attr_accessor :rank
|
15
13
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: csv_record
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.
|
4
|
+
version: 1.7.0
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2012-11-
|
12
|
+
date: 2012-11-28 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: activesupport
|