csv_record 1.0.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/.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
|