csv_record 1.6.0 → 1.7.0

Sign up to get free protection for your applications and to get access to all the features.
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
- By including this module you will gain for free the following methods:
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
- car.valid? # verifies its validity, specially if it is declared some of the available validators (e.x:validates_presence_of).
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
- validates_presence_of :name
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 :name => ''
180
+ company = Company.create
153
181
  company.save
154
182
  # => false
155
183
 
156
- company = Company.create :name => ''
184
+ company = Company.create
157
185
  company.valid?
158
186
  # => false
159
187
  company.invalid?
@@ -1,12 +1,13 @@
1
1
  module CsvRecord
2
2
  module Callbacks
3
-
4
3
  CALLBACKS = [
5
- :after_create,
6
4
  :after_initialize,
7
- :after_save,
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
@@ -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? 'db'
5
- Dir.mkdir 'db'
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
- initialize_db_directory
15
+ __initialize_db_directory__
11
16
  unless db_initialized?
12
- open_database_file 'wb' do |csv|
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='r')
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'), 'w', headers: true) do |copy|
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)
@@ -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
- attr_writer :fields_to_validate
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
- def fields_to_validate
7
- @fields_to_validate || []
13
+ eval "alias :validates_#{kind}_of :__validates_#{kind}_of__"
8
14
  end
9
15
 
10
- def __validates_presence_of__(*attr_names)
11
- @fields_to_validate = attr_names
16
+ def custom_validators
17
+ @custom_validators || []
12
18
  end
13
19
 
14
- alias :validates_presence_of :__validates_presence_of__
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
- validate_each(self.class.fields_to_validate)
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 validate_each(attributes)
35
- attributes.each do |attribute|
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
@@ -1,3 +1,3 @@
1
1
  module CsvRecord
2
- VERSION = "1.6.0"
2
+ VERSION = "1.7.0"
3
3
  end
@@ -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 'a' do |csv|
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 "Retrieves all registries" do
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
@@ -1,5 +1,3 @@
1
- require 'csv_record'
2
-
3
1
  class Car
4
2
  include CsvRecord::Document
5
3
 
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
- attr_accessor :name, :age, :midi_chlorians
25
+ private
26
+ def my_custom_validator_method
27
+ @custom_validator_checker = true
28
+ end
17
29
  end
@@ -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.6.0
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-23 00:00:00.000000000 Z
12
+ date: 2012-11-28 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: activesupport