csv_record 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +17 -0
- data/Gemfile +4 -0
- data/LICENSE +22 -0
- data/README.md +82 -0
- data/Rakefile +12 -0
- data/csv_record.gemspec +21 -0
- data/lib/csv_record/callbacks.rb +40 -0
- data/lib/csv_record/connector.rb +55 -0
- data/lib/csv_record/document.rb +31 -0
- data/lib/csv_record/helpers.rb +11 -0
- data/lib/csv_record/reader.rb +46 -0
- data/lib/csv_record/timestamps.rb +35 -0
- data/lib/csv_record/version.rb +3 -0
- data/lib/csv_record/writer.rb +87 -0
- data/lib/csv_record.rb +41 -0
- data/test/csv_record/callbacks_test.rb +38 -0
- data/test/csv_record/connector_test.rb +30 -0
- data/test/csv_record/csv_record_test.rb +8 -0
- data/test/csv_record/document_test.rb +6 -0
- data/test/csv_record/helpers_test.rb +12 -0
- data/test/csv_record/reader_test.rb +74 -0
- data/test/csv_record/timestamps_test.rb +45 -0
- data/test/csv_record/writer_test.rb +109 -0
- data/test/models/callback_test_class.rb +16 -0
- data/test/models/car.rb +13 -0
- data/test/test_helper.rb +27 -0
- metadata +131 -0
data/.gitignore
ADDED
data/Gemfile
ADDED
data/LICENSE
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2012 Lukas Alexandre
|
2
|
+
|
3
|
+
MIT License
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
6
|
+
a copy of this software and associated documentation files (the
|
7
|
+
"Software"), to deal in the Software without restriction, including
|
8
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
9
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
10
|
+
permit persons to whom the Software is furnished to do so, subject to
|
11
|
+
the following conditions:
|
12
|
+
|
13
|
+
The above copyright notice and this permission notice shall be
|
14
|
+
included in all copies or substantial portions of the Software.
|
15
|
+
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
19
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
20
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
21
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
22
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,82 @@
|
|
1
|
+
# CsvRecord
|
2
|
+
|
3
|
+
CSV Record connects classes to CSV documents database to establish an almost zero-configuration persistence layer for applications.
|
4
|
+
|
5
|
+
## Installation
|
6
|
+
|
7
|
+
Add this line to your application's Gemfile:
|
8
|
+
|
9
|
+
```ruby
|
10
|
+
gem 'csv_record'
|
11
|
+
```
|
12
|
+
|
13
|
+
And then execute:
|
14
|
+
|
15
|
+
```
|
16
|
+
$ bundle
|
17
|
+
```
|
18
|
+
|
19
|
+
Or install it yourself as:
|
20
|
+
|
21
|
+
```
|
22
|
+
$ gem install csv_record
|
23
|
+
```
|
24
|
+
|
25
|
+
## Usage
|
26
|
+
|
27
|
+
```ruby
|
28
|
+
class Car
|
29
|
+
include CsvRecord::Document
|
30
|
+
end
|
31
|
+
```
|
32
|
+
|
33
|
+
By including this module you will gain for free the following methods:
|
34
|
+
|
35
|
+
```ruby
|
36
|
+
Car.create( # save the new record in the database
|
37
|
+
year: 2007,
|
38
|
+
make: 'Chevrolet',
|
39
|
+
model: 'F450',
|
40
|
+
description: 'ac, abs, moon',
|
41
|
+
price: 5000.00
|
42
|
+
)
|
43
|
+
|
44
|
+
car.save # save the record in the database (either creating or changing)
|
45
|
+
|
46
|
+
car.update_attribute :year, 1999 # update a single field of an object
|
47
|
+
|
48
|
+
car.destroy # removes the record from the database
|
49
|
+
|
50
|
+
car.new_record? # checks if the record is new
|
51
|
+
|
52
|
+
Class.all # retrieves all saved records
|
53
|
+
|
54
|
+
Class.find car.id # find through its id
|
55
|
+
Class.find car # find through the record
|
56
|
+
|
57
|
+
Car.count # returns the amount of records in the database
|
58
|
+
```
|
59
|
+
|
60
|
+
##Callbacks
|
61
|
+
Callbacks can be used to execute code on predetermined moments.
|
62
|
+
|
63
|
+
```ruby
|
64
|
+
before_create do |obj|
|
65
|
+
obj.do_something
|
66
|
+
end
|
67
|
+
|
68
|
+
after_create do |obj|
|
69
|
+
obj.do_something
|
70
|
+
end
|
71
|
+
```
|
72
|
+
|
73
|
+
##Precautions
|
74
|
+
CsvRecord creates a `db` folder in the root of your application. Be sure that it has permission to do so.
|
75
|
+
|
76
|
+
## Contributing
|
77
|
+
|
78
|
+
1. Fork it
|
79
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
80
|
+
3. Commit your changes (`git commit -am 'Added some feature'`)
|
81
|
+
4. Push to the branch (`git push origin my-new-feature`)
|
82
|
+
5. Create new Pull Request
|
data/Rakefile
ADDED
data/csv_record.gemspec
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
require File.expand_path('../lib/csv_record/version', __FILE__)
|
3
|
+
|
4
|
+
Gem::Specification.new do |gem|
|
5
|
+
gem.authors = ["Lukas Alexandre"]
|
6
|
+
gem.email = ["lukeskytm@gmail.com"]
|
7
|
+
gem.description = %q{CSV Object-relational mapping}
|
8
|
+
gem.summary = %q{CSV Record connects classes to CSV documents database to establish an almost zero-configuration persistence layer for applications.}
|
9
|
+
gem.homepage = "https://github.com/lukasalexandre/csv_record"
|
10
|
+
|
11
|
+
gem.files = `git ls-files`.split($\)
|
12
|
+
gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
|
13
|
+
gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
|
14
|
+
gem.name = "csv_record"
|
15
|
+
gem.require_paths = ["lib"]
|
16
|
+
gem.version = CsvRecord::VERSION
|
17
|
+
|
18
|
+
gem.add_development_dependency 'rake'
|
19
|
+
gem.add_development_dependency 'timecop'
|
20
|
+
gem.add_development_dependency 'turn'
|
21
|
+
end
|
@@ -0,0 +1,40 @@
|
|
1
|
+
module CsvRecord
|
2
|
+
module Callbacks
|
3
|
+
CALLBACKS = [
|
4
|
+
:after_create,
|
5
|
+
:after_initialize,
|
6
|
+
:after_save,
|
7
|
+
:before_create,
|
8
|
+
:before_save,
|
9
|
+
].freeze
|
10
|
+
|
11
|
+
module ClassMethods
|
12
|
+
CALLBACKS.each do |callback|
|
13
|
+
define_method callback do |*args, &block|
|
14
|
+
const_variable = "#{callback}_callbacks".upcase
|
15
|
+
const_set(const_variable, []) unless const_defined? const_variable
|
16
|
+
const_get(const_variable) << block if block
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
module InstanceMethods
|
22
|
+
CALLBACKS.each do |callback|
|
23
|
+
define_method "run_#{callback}_callbacks" do
|
24
|
+
const_variable = "#{callback}_callbacks".upcase
|
25
|
+
if self.class.const_defined? const_variable
|
26
|
+
callbacks_collection = self.class.const_get("#{callback}_callbacks".upcase)
|
27
|
+
callbacks_collection.each do |callback_proc|
|
28
|
+
callback_proc.call self
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
def self.included(receiver)
|
36
|
+
receiver.extend ClassMethods
|
37
|
+
receiver.send :include, InstanceMethods
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
@@ -0,0 +1,55 @@
|
|
1
|
+
module CsvRecord
|
2
|
+
module Connector
|
3
|
+
def __initialize_db_directory__
|
4
|
+
unless Dir.exists? 'db'
|
5
|
+
FileUtils.mkdir_p('db')
|
6
|
+
end
|
7
|
+
end
|
8
|
+
|
9
|
+
def __initialize_db__
|
10
|
+
initialize_db_directory
|
11
|
+
unless db_initialized?
|
12
|
+
open_database_file 'wb' do |csv|
|
13
|
+
csv << fields
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
def db_initialized?
|
19
|
+
File.exist? self.const_get('DATABASE_LOCATION')
|
20
|
+
end
|
21
|
+
|
22
|
+
def __open_database_file__(mode='r')
|
23
|
+
CSV.open(self.const_get('DATABASE_LOCATION'), mode, :headers => true) do |csv|
|
24
|
+
yield(csv)
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
def __parse_database_file__
|
29
|
+
open_database_file do |csv|
|
30
|
+
CSV.open(self.const_get('DATABASE_LOCATION_TMP'), 'w', :headers => true) do |copy|
|
31
|
+
copy << fields
|
32
|
+
csv.entries.each do |entry|
|
33
|
+
new_row = yield(entry)
|
34
|
+
copy << new_row if new_row
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
rename_database
|
39
|
+
end
|
40
|
+
|
41
|
+
protected
|
42
|
+
|
43
|
+
def rename_database
|
44
|
+
old_file = self.const_get('DATABASE_LOCATION')
|
45
|
+
tmp_file = self.const_get('DATABASE_LOCATION_TMP')
|
46
|
+
File.delete old_file
|
47
|
+
File.rename(tmp_file, old_file)
|
48
|
+
end
|
49
|
+
|
50
|
+
alias :initialize_db_directory :__initialize_db_directory__
|
51
|
+
alias :initialize_db :__initialize_db__
|
52
|
+
alias :open_database_file :__open_database_file__
|
53
|
+
alias :parse_database_file :__parse_database_file__
|
54
|
+
end
|
55
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
require 'csv_record/connector'
|
2
|
+
require 'csv_record/writer'
|
3
|
+
require 'csv_record/reader'
|
4
|
+
require 'csv_record/timestamps'
|
5
|
+
require 'csv_record/callbacks'
|
6
|
+
require 'csv_record/helpers'
|
7
|
+
|
8
|
+
module CsvRecord
|
9
|
+
|
10
|
+
# This is the base module for all domain objects that need to be persisted to
|
11
|
+
# the database.
|
12
|
+
module Document
|
13
|
+
def self.included(receiver)
|
14
|
+
self.const_set('DATABASE_LOCATION',"db/#{parse_caller(caller[1]).downcase}.csv")
|
15
|
+
self.const_set('DATABASE_LOCATION_TMP',"db/#{parse_caller(caller[1]).downcase}_tmp.csv")
|
16
|
+
|
17
|
+
receiver.extend CsvRecord::Connector
|
18
|
+
receiver.extend CsvRecord::Writer::ClassMethods
|
19
|
+
receiver.extend CsvRecord::Reader::ClassMethods
|
20
|
+
receiver.send :include, CsvRecord::Writer::InstanceMethods
|
21
|
+
receiver.send :include, CsvRecord::Reader::InstanceMethods
|
22
|
+
receiver.send :include, CsvRecord::Timestamps
|
23
|
+
receiver.send :include, CsvRecord::Callbacks
|
24
|
+
end
|
25
|
+
|
26
|
+
def self.parse_caller(at)
|
27
|
+
/(?:(\<class\:)(\w+))/ =~ at
|
28
|
+
$2
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
@@ -0,0 +1,46 @@
|
|
1
|
+
module CsvRecord
|
2
|
+
module Reader
|
3
|
+
module ClassMethods
|
4
|
+
def __fields__
|
5
|
+
instance_methods(false).select { |m| m.to_s !~ /=$/ }
|
6
|
+
end
|
7
|
+
|
8
|
+
def all
|
9
|
+
open_database_file do |csv|
|
10
|
+
csv.entries.map { |attributes| self.new attributes }
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
def __count__
|
15
|
+
open_database_file do |csv|
|
16
|
+
csv.entries.size
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
def __find__(param)
|
21
|
+
param = param.id unless param.is_a? Integer
|
22
|
+
open_database_file do |csv|
|
23
|
+
row = csv.entries.select { |attributes| attributes['id'].to_i == param }.first
|
24
|
+
self.new row.to_hash
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
alias :fields :__fields__
|
29
|
+
alias :find :__find__
|
30
|
+
alias :count :__count__
|
31
|
+
end
|
32
|
+
|
33
|
+
module InstanceMethods
|
34
|
+
def __values__
|
35
|
+
self.class.fields.map { |attribute| self.public_send(attribute) }
|
36
|
+
end
|
37
|
+
|
38
|
+
def __attributes__
|
39
|
+
Hash[self.class.fields.zip self.values]
|
40
|
+
end
|
41
|
+
|
42
|
+
alias :attributes :__attributes__
|
43
|
+
alias :values :__values__
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
module CsvRecord
|
2
|
+
# This module handles the behaviour for setting up document created at
|
3
|
+
# timestamp.
|
4
|
+
module Timestamps
|
5
|
+
def self.included(receiver)
|
6
|
+
receiver.send :attr_accessor, :created_at
|
7
|
+
receiver.send :attr_accessor, :updated_at
|
8
|
+
end
|
9
|
+
|
10
|
+
# Update the created_at field on the Document to the current time. This is
|
11
|
+
# only called on create.
|
12
|
+
#
|
13
|
+
# @example Set the created at time.
|
14
|
+
# person.set_created_at
|
15
|
+
def __set_created_at__
|
16
|
+
if !created_at
|
17
|
+
time = Time.now.utc
|
18
|
+
@created_at = time
|
19
|
+
@updated_at = time
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
# Update the created_at field on the Document to the current time. This is
|
24
|
+
# called on each save.
|
25
|
+
#
|
26
|
+
# @example Set the updated at time.
|
27
|
+
# person.set_updated_at
|
28
|
+
def __set_updated_at__
|
29
|
+
@updated_at = Time.now.utc
|
30
|
+
end
|
31
|
+
|
32
|
+
alias :set_created_at :__set_created_at__
|
33
|
+
alias :set_updated_at :__set_updated_at__
|
34
|
+
end
|
35
|
+
end
|
@@ -0,0 +1,87 @@
|
|
1
|
+
require 'csv'
|
2
|
+
|
3
|
+
module CsvRecord
|
4
|
+
module Writer
|
5
|
+
module ClassMethods
|
6
|
+
def __create__(attributes={})
|
7
|
+
instance = self.new attributes
|
8
|
+
instance.run_before_create_callbacks
|
9
|
+
result = instance.save
|
10
|
+
instance.run_after_create_callbacks if result
|
11
|
+
instance
|
12
|
+
end
|
13
|
+
|
14
|
+
alias :create :__create__
|
15
|
+
end
|
16
|
+
|
17
|
+
module InstanceMethods
|
18
|
+
def self.included(receiver)
|
19
|
+
receiver.send :attr_accessor, :id
|
20
|
+
end
|
21
|
+
|
22
|
+
def __save__
|
23
|
+
self.new_record? ? self.append_registry : self.update_registry
|
24
|
+
end
|
25
|
+
|
26
|
+
def new_record?
|
27
|
+
self.created_at.nil? || self.id.nil?
|
28
|
+
end
|
29
|
+
|
30
|
+
def __update_attribute__(field, value)
|
31
|
+
self.public_send "#{field}=", value
|
32
|
+
self.save
|
33
|
+
end
|
34
|
+
|
35
|
+
def __destroy__
|
36
|
+
self.class.parse_database_file do |row|
|
37
|
+
new_row = row
|
38
|
+
new_row = nil if self.id == row.field('id').to_i
|
39
|
+
new_row
|
40
|
+
end
|
41
|
+
empty_fields
|
42
|
+
true
|
43
|
+
end
|
44
|
+
|
45
|
+
protected
|
46
|
+
|
47
|
+
def calculate_id
|
48
|
+
@id = Car.count + 1
|
49
|
+
end
|
50
|
+
|
51
|
+
def append_registry
|
52
|
+
Car.initialize_db
|
53
|
+
set_created_at
|
54
|
+
write_object
|
55
|
+
end
|
56
|
+
|
57
|
+
def update_registry
|
58
|
+
set_updated_at
|
59
|
+
self.class.parse_database_file do |row|
|
60
|
+
new_row = row
|
61
|
+
new_row = self.values if self.id == row.field('id').to_i
|
62
|
+
new_row
|
63
|
+
end
|
64
|
+
true
|
65
|
+
end
|
66
|
+
|
67
|
+
def __write_object__
|
68
|
+
calculate_id
|
69
|
+
self.class.open_database_file 'a' do |csv|
|
70
|
+
csv << values
|
71
|
+
end
|
72
|
+
true
|
73
|
+
end
|
74
|
+
|
75
|
+
def empty_fields
|
76
|
+
%w(id created_at updated_at).each do |field|
|
77
|
+
self.public_send "#{field}=", nil
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
alias :save :__save__
|
82
|
+
alias :write_object :__write_object__
|
83
|
+
alias :update_attribute :__update_attribute__
|
84
|
+
alias :destroy :__destroy__
|
85
|
+
end
|
86
|
+
end
|
87
|
+
end
|
data/lib/csv_record.rb
ADDED
@@ -0,0 +1,41 @@
|
|
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
|
+
require 'csv'
|
25
|
+
|
26
|
+
require 'csv_record/document'
|
27
|
+
|
28
|
+
require "csv_record/version"
|
29
|
+
|
30
|
+
module CsvRecord
|
31
|
+
# Sets the CsvRecord configuration options. Best used by passing a block.
|
32
|
+
#
|
33
|
+
# @example Set up configuration options.
|
34
|
+
# CsvRecord.configure do |config|
|
35
|
+
# end
|
36
|
+
#
|
37
|
+
# @return [ self ] The CsvRecord object.
|
38
|
+
def configure
|
39
|
+
block_given? ? yield(self) : self
|
40
|
+
end
|
41
|
+
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
require_relative '../test_helper'
|
2
|
+
|
3
|
+
require_relative '../models/car'
|
4
|
+
require_relative '../models/callback_test_class'
|
5
|
+
|
6
|
+
describe CsvRecord::Callbacks do
|
7
|
+
describe "Check the callback definitions" do
|
8
|
+
let (:klass) { CallbackTestClass }
|
9
|
+
|
10
|
+
it ('before_create callback') { klass.must_respond_to(:before_create) }
|
11
|
+
it ('after_create callback') { klass.must_respond_to(:after_create) }
|
12
|
+
it ('before_save callback') { klass.must_respond_to(:before_save) }
|
13
|
+
it ('after_save callback') { klass.must_respond_to(:after_save) }
|
14
|
+
it ('after_initialize callback') { klass.must_respond_to(:after_initialize) }
|
15
|
+
end
|
16
|
+
|
17
|
+
describe "Check the run callback definitions" do
|
18
|
+
let (:klass) { CallbackTestClass.new }
|
19
|
+
|
20
|
+
it ('run before_create callbacks') { klass.must_respond_to(:run_before_create_callbacks) }
|
21
|
+
it ('run after_create callbacks') { klass.must_respond_to(:run_after_create_callbacks) }
|
22
|
+
it ('run before_save callbacks') { klass.must_respond_to(:run_before_save_callbacks) }
|
23
|
+
it ('run after_save callbacks') { klass.must_respond_to(:run_after_save_callbacks) }
|
24
|
+
it ('run after_initialize callbacks') { klass.must_respond_to(:run_after_initialize_callbacks) }
|
25
|
+
end
|
26
|
+
|
27
|
+
describe 'Checking the callbacks execution' do
|
28
|
+
let (:object_created) { CallbackTestClass.create }
|
29
|
+
|
30
|
+
it 'before_create' do
|
31
|
+
object_created.before_create_called.must_equal true
|
32
|
+
end
|
33
|
+
|
34
|
+
it 'after_create' do
|
35
|
+
object_created.after_create_called.must_equal true
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
require_relative '../test_helper'
|
2
|
+
|
3
|
+
require_relative '../models/car'
|
4
|
+
|
5
|
+
describe CsvRecord::Connector do
|
6
|
+
describe 'initializing methods' do
|
7
|
+
it ('responds to initialize_db_directory') { Car.must_respond_to :initialize_db_directory }
|
8
|
+
it ('responds to initialize_db') { Car.must_respond_to :initialize_db }
|
9
|
+
it ('responds to db_initialized?') { Car.must_respond_to :db_initialized? }
|
10
|
+
it ('responds to open_database_file') { Car.must_respond_to :open_database_file }
|
11
|
+
end
|
12
|
+
|
13
|
+
describe 'validating the methods behavior' do
|
14
|
+
it "Creates the database folder" do
|
15
|
+
Car.initialize_db_directory.wont_be_nil
|
16
|
+
Dir.exists?('db').must_equal true
|
17
|
+
end
|
18
|
+
|
19
|
+
it "Checks the database initialization state" do
|
20
|
+
Car.db_initialized?.must_equal false
|
21
|
+
car.save
|
22
|
+
Car.db_initialized?.must_equal true
|
23
|
+
end
|
24
|
+
|
25
|
+
it "Creates the database file" do
|
26
|
+
car.save
|
27
|
+
File.exists?(Car::DATABASE_LOCATION).must_equal true
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
@@ -0,0 +1,74 @@
|
|
1
|
+
require_relative '../test_helper'
|
2
|
+
|
3
|
+
require_relative '../models/car'
|
4
|
+
|
5
|
+
describe CsvRecord::Reader do
|
6
|
+
describe 'initializing class methods' do
|
7
|
+
it ('responds to fields') { Car.must_respond_to :fields }
|
8
|
+
it ('responds to all') { Car.must_respond_to :all }
|
9
|
+
end
|
10
|
+
|
11
|
+
describe 'initializing instance methods' do
|
12
|
+
it ('responds to values') { Car.new.must_respond_to :values }
|
13
|
+
it ('responds to attributes') { Car.new.must_respond_to :attributes }
|
14
|
+
end
|
15
|
+
|
16
|
+
describe 'validating the methods behavior' do
|
17
|
+
let(:second_car) do
|
18
|
+
Car.new(
|
19
|
+
year: 2007,
|
20
|
+
make: 'Chevrolet',
|
21
|
+
model: 'F450',
|
22
|
+
description: 'ac, abs, moon',
|
23
|
+
price: 5000.00
|
24
|
+
)
|
25
|
+
end
|
26
|
+
|
27
|
+
it "Check the current fields" do
|
28
|
+
Car.fields.must_equal [:id, :created_at, :updated_at, :year, :make, :model, :description, :price]
|
29
|
+
end
|
30
|
+
|
31
|
+
it "Check the current values" do
|
32
|
+
car.values.must_equal [nil, nil, nil, 1997, 'Ford', 'E350', 'ac, abs, moon', 3000.00]
|
33
|
+
end
|
34
|
+
|
35
|
+
it "Check the current attributes" do
|
36
|
+
expected_result = {:id=>nil, :created_at=>nil, :updated_at=>nil, :year=>1997, :make=>"Ford", :model=>"E350", :description=>"ac, abs, moon", :price=>3000.0}
|
37
|
+
car.attributes.must_equal expected_result
|
38
|
+
end
|
39
|
+
|
40
|
+
it "Retrieves all registries" do
|
41
|
+
car.save
|
42
|
+
Car.all.size.must_equal 1
|
43
|
+
second_car.save
|
44
|
+
Car.all.size.must_equal 2
|
45
|
+
end
|
46
|
+
|
47
|
+
it "Retrieves all registries" do
|
48
|
+
car.save
|
49
|
+
Car.count.must_equal 1
|
50
|
+
second_car.save
|
51
|
+
Car.count.must_equal 2
|
52
|
+
end
|
53
|
+
|
54
|
+
it 'querying by id' do
|
55
|
+
cars = []
|
56
|
+
3.times do
|
57
|
+
cars << car.clone
|
58
|
+
cars.last.save
|
59
|
+
end
|
60
|
+
Car.find(cars.first.id).wont_be_nil
|
61
|
+
Car.find(cars.first.id).must_be_instance_of Car
|
62
|
+
end
|
63
|
+
|
64
|
+
it 'querying by object' do
|
65
|
+
cars = []
|
66
|
+
3.times do
|
67
|
+
cars << car.clone
|
68
|
+
cars.last.save
|
69
|
+
end
|
70
|
+
Car.find(cars.first).wont_be_nil
|
71
|
+
Car.find(cars.first.id).must_be_instance_of Car
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
@@ -0,0 +1,45 @@
|
|
1
|
+
require_relative '../test_helper'
|
2
|
+
|
3
|
+
require 'timecop'
|
4
|
+
|
5
|
+
require_relative '../models/car'
|
6
|
+
|
7
|
+
describe CsvRecord::Timestamps do
|
8
|
+
describe 'initializing instance methods' do
|
9
|
+
it ('responds to created_at') { car.must_respond_to :created_at }
|
10
|
+
it ('responds to set_created_at') { car.must_respond_to :set_created_at }
|
11
|
+
end
|
12
|
+
|
13
|
+
describe 'checking if it`s extracting the right fields' do
|
14
|
+
it ('checking created_at') { Car.fields.must_include :created_at }
|
15
|
+
end
|
16
|
+
|
17
|
+
describe 'defines on create' do
|
18
|
+
before do
|
19
|
+
Timecop.freeze(Time.now.utc)
|
20
|
+
end
|
21
|
+
|
22
|
+
after do
|
23
|
+
Timecop.return
|
24
|
+
end
|
25
|
+
|
26
|
+
it 'sets the time wich the object was created' do
|
27
|
+
car.save
|
28
|
+
car.created_at.must_equal Time.now.utc
|
29
|
+
end
|
30
|
+
|
31
|
+
it 'sets the updated time on created' do
|
32
|
+
car.save
|
33
|
+
car.updated_at.must_equal Time.now.utc
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
describe 'update on update' do
|
38
|
+
it 'sets the updated_at attribute on every save' do
|
39
|
+
car.save
|
40
|
+
previous_time = car.updated_at
|
41
|
+
car.update_attribute :year, '1800'
|
42
|
+
car.updated_at.wont_equal previous_time
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
@@ -0,0 +1,109 @@
|
|
1
|
+
require_relative '../test_helper'
|
2
|
+
|
3
|
+
require_relative '../models/car'
|
4
|
+
|
5
|
+
describe CsvRecord::Writer do
|
6
|
+
describe 'initializing class methods' do
|
7
|
+
it 'responds to create' do
|
8
|
+
Car.must_respond_to :create
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
describe 'initializing instance methods' do
|
13
|
+
it ('responds to save') { car.must_respond_to :save }
|
14
|
+
it ('responds to new_record?') { car.must_respond_to :new_record? }
|
15
|
+
it ('responds to calculate_id') { car.must_respond_to :calculate_id }
|
16
|
+
it ('responds to write_object') { car.must_respond_to :write_object }
|
17
|
+
it ('responds to id') { car.must_respond_to :id }
|
18
|
+
it ('responds to update_attribute') { car.must_respond_to :update_attribute }
|
19
|
+
it ('responds to destroy') { car.must_respond_to :destroy }
|
20
|
+
end
|
21
|
+
|
22
|
+
describe 'validating the methods behavior' do
|
23
|
+
let(:second_car) do
|
24
|
+
Car.new(
|
25
|
+
year: 2007,
|
26
|
+
make: 'Chevrolet',
|
27
|
+
model: 'F450',
|
28
|
+
description: 'ac, abs, moon',
|
29
|
+
price: 5000.00
|
30
|
+
)
|
31
|
+
end
|
32
|
+
|
33
|
+
describe 'create' do
|
34
|
+
it "Creates more than one registry" do
|
35
|
+
car.save
|
36
|
+
second_car.save
|
37
|
+
Car.all.size.must_equal 2
|
38
|
+
end
|
39
|
+
|
40
|
+
it "Creates the object through create method" do
|
41
|
+
created_car = Car.create(
|
42
|
+
year: 2007,
|
43
|
+
make: 'Chevrolet',
|
44
|
+
model: 'F450',
|
45
|
+
description: 'ac, abs, moon',
|
46
|
+
price: 5000.00
|
47
|
+
)
|
48
|
+
created_car.wont_be_nil
|
49
|
+
created_car.must_be_instance_of Car
|
50
|
+
created_car.new_record?.must_equal false
|
51
|
+
end
|
52
|
+
|
53
|
+
it "Sets the ID of the created object" do
|
54
|
+
car.id.must_be_nil
|
55
|
+
car.save
|
56
|
+
car.id.must_equal 1
|
57
|
+
second_car.save
|
58
|
+
second_car.id.must_equal 2
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
describe 'new_record' do
|
63
|
+
it "Checks whether is a new record" do
|
64
|
+
car.new_record?.must_equal true
|
65
|
+
car.save
|
66
|
+
car.new_record?.must_equal false
|
67
|
+
end
|
68
|
+
|
69
|
+
it "Checks whether a previously saved record is a new record" do
|
70
|
+
car.save
|
71
|
+
Car.find(car).new_record?.must_equal false
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
describe 'updates' do
|
76
|
+
it "Updates a single field" do
|
77
|
+
car.save
|
78
|
+
car.update_attribute :year, 2008
|
79
|
+
Car.find(car).year.must_equal '2008'
|
80
|
+
end
|
81
|
+
|
82
|
+
it "Updates multiple fields using save" do
|
83
|
+
car.save
|
84
|
+
car.year = 2008
|
85
|
+
car.model = 'E846'
|
86
|
+
car.save
|
87
|
+
retrieved_car = Car.find(car)
|
88
|
+
retrieved_car.year.must_equal '2008'
|
89
|
+
retrieved_car.model.must_equal 'E846'
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
describe 'destroy' do
|
94
|
+
it 'remove the object from the database' do
|
95
|
+
car.save
|
96
|
+
car.destroy
|
97
|
+
Car.count.must_equal 0
|
98
|
+
end
|
99
|
+
|
100
|
+
it 'by destroying the object its timestamps and id should be empty' do
|
101
|
+
car.save
|
102
|
+
car.destroy
|
103
|
+
car.id.must_be_nil
|
104
|
+
car.created_at.must_be_nil
|
105
|
+
car.updated_at.must_be_nil
|
106
|
+
end
|
107
|
+
end
|
108
|
+
end
|
109
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
class CallbackTestClass
|
2
|
+
include CsvRecord::Document
|
3
|
+
|
4
|
+
def initialize(*args)
|
5
|
+
end
|
6
|
+
|
7
|
+
attr_accessor :before_create_called, :after_create_called
|
8
|
+
|
9
|
+
before_create do |obj|
|
10
|
+
obj.before_create_called = true
|
11
|
+
end
|
12
|
+
|
13
|
+
after_create do |obj|
|
14
|
+
obj.after_create_called = true
|
15
|
+
end
|
16
|
+
end
|
data/test/models/car.rb
ADDED
data/test/test_helper.rb
ADDED
@@ -0,0 +1,27 @@
|
|
1
|
+
require 'minitest/spec'
|
2
|
+
require 'minitest/autorun'
|
3
|
+
require 'turn'
|
4
|
+
|
5
|
+
module TestHelper
|
6
|
+
BASE_PATH = File.expand_path("../fixtures", __FILE__)
|
7
|
+
|
8
|
+
def fetch_fixture_path(path)
|
9
|
+
File.join(BASE_PATH, path)
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
class MiniTest::Spec
|
14
|
+
after :each do
|
15
|
+
FileUtils.rm_rf 'db'
|
16
|
+
end
|
17
|
+
|
18
|
+
let(:car) do
|
19
|
+
Car.new(
|
20
|
+
year: 1997,
|
21
|
+
make: 'Ford',
|
22
|
+
model: 'E350',
|
23
|
+
description: 'ac, abs, moon',
|
24
|
+
price: 3000.00
|
25
|
+
)
|
26
|
+
end
|
27
|
+
end
|
metadata
ADDED
@@ -0,0 +1,131 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: csv_record
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 1.0.0
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Lukas Alexandre
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2012-10-29 00:00:00.000000000 Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: rake
|
16
|
+
requirement: !ruby/object:Gem::Requirement
|
17
|
+
none: false
|
18
|
+
requirements:
|
19
|
+
- - ! '>='
|
20
|
+
- !ruby/object:Gem::Version
|
21
|
+
version: '0'
|
22
|
+
type: :development
|
23
|
+
prerelease: false
|
24
|
+
version_requirements: !ruby/object:Gem::Requirement
|
25
|
+
none: false
|
26
|
+
requirements:
|
27
|
+
- - ! '>='
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
version: '0'
|
30
|
+
- !ruby/object:Gem::Dependency
|
31
|
+
name: timecop
|
32
|
+
requirement: !ruby/object:Gem::Requirement
|
33
|
+
none: false
|
34
|
+
requirements:
|
35
|
+
- - ! '>='
|
36
|
+
- !ruby/object:Gem::Version
|
37
|
+
version: '0'
|
38
|
+
type: :development
|
39
|
+
prerelease: false
|
40
|
+
version_requirements: !ruby/object:Gem::Requirement
|
41
|
+
none: false
|
42
|
+
requirements:
|
43
|
+
- - ! '>='
|
44
|
+
- !ruby/object:Gem::Version
|
45
|
+
version: '0'
|
46
|
+
- !ruby/object:Gem::Dependency
|
47
|
+
name: turn
|
48
|
+
requirement: !ruby/object:Gem::Requirement
|
49
|
+
none: false
|
50
|
+
requirements:
|
51
|
+
- - ! '>='
|
52
|
+
- !ruby/object:Gem::Version
|
53
|
+
version: '0'
|
54
|
+
type: :development
|
55
|
+
prerelease: false
|
56
|
+
version_requirements: !ruby/object:Gem::Requirement
|
57
|
+
none: false
|
58
|
+
requirements:
|
59
|
+
- - ! '>='
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '0'
|
62
|
+
description: CSV Object-relational mapping
|
63
|
+
email:
|
64
|
+
- lukeskytm@gmail.com
|
65
|
+
executables: []
|
66
|
+
extensions: []
|
67
|
+
extra_rdoc_files: []
|
68
|
+
files:
|
69
|
+
- .gitignore
|
70
|
+
- Gemfile
|
71
|
+
- LICENSE
|
72
|
+
- README.md
|
73
|
+
- Rakefile
|
74
|
+
- csv_record.gemspec
|
75
|
+
- lib/csv_record.rb
|
76
|
+
- lib/csv_record/callbacks.rb
|
77
|
+
- lib/csv_record/connector.rb
|
78
|
+
- lib/csv_record/document.rb
|
79
|
+
- lib/csv_record/helpers.rb
|
80
|
+
- lib/csv_record/reader.rb
|
81
|
+
- lib/csv_record/timestamps.rb
|
82
|
+
- lib/csv_record/version.rb
|
83
|
+
- lib/csv_record/writer.rb
|
84
|
+
- test/csv_record/callbacks_test.rb
|
85
|
+
- test/csv_record/connector_test.rb
|
86
|
+
- test/csv_record/csv_record_test.rb
|
87
|
+
- test/csv_record/document_test.rb
|
88
|
+
- test/csv_record/helpers_test.rb
|
89
|
+
- test/csv_record/reader_test.rb
|
90
|
+
- test/csv_record/timestamps_test.rb
|
91
|
+
- test/csv_record/writer_test.rb
|
92
|
+
- test/models/callback_test_class.rb
|
93
|
+
- test/models/car.rb
|
94
|
+
- test/test_helper.rb
|
95
|
+
homepage: https://github.com/lukasalexandre/csv_record
|
96
|
+
licenses: []
|
97
|
+
post_install_message:
|
98
|
+
rdoc_options: []
|
99
|
+
require_paths:
|
100
|
+
- lib
|
101
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
102
|
+
none: false
|
103
|
+
requirements:
|
104
|
+
- - ! '>='
|
105
|
+
- !ruby/object:Gem::Version
|
106
|
+
version: '0'
|
107
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
108
|
+
none: false
|
109
|
+
requirements:
|
110
|
+
- - ! '>='
|
111
|
+
- !ruby/object:Gem::Version
|
112
|
+
version: '0'
|
113
|
+
requirements: []
|
114
|
+
rubyforge_project:
|
115
|
+
rubygems_version: 1.8.24
|
116
|
+
signing_key:
|
117
|
+
specification_version: 3
|
118
|
+
summary: CSV Record connects classes to CSV documents database to establish an almost
|
119
|
+
zero-configuration persistence layer for applications.
|
120
|
+
test_files:
|
121
|
+
- test/csv_record/callbacks_test.rb
|
122
|
+
- test/csv_record/connector_test.rb
|
123
|
+
- test/csv_record/csv_record_test.rb
|
124
|
+
- test/csv_record/document_test.rb
|
125
|
+
- test/csv_record/helpers_test.rb
|
126
|
+
- test/csv_record/reader_test.rb
|
127
|
+
- test/csv_record/timestamps_test.rb
|
128
|
+
- test/csv_record/writer_test.rb
|
129
|
+
- test/models/callback_test_class.rb
|
130
|
+
- test/models/car.rb
|
131
|
+
- test/test_helper.rb
|