csv_record 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
data/.gitignore ADDED
@@ -0,0 +1,17 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ Gemfile.lock
7
+ InstalledFiles
8
+ _yardoc
9
+ coverage
10
+ doc/
11
+ lib/bundler/man
12
+ pkg
13
+ rdoc
14
+ spec/reports
15
+ test/tmp
16
+ test/version_tmp
17
+ tmp
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in csv_record.gemspec
4
+ gemspec
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
@@ -0,0 +1,12 @@
1
+ #!/usr/bin/env rake
2
+ require "bundler/gem_tasks"
3
+ require "rake/testtask"
4
+
5
+ Rake::TestTask.new do |t|
6
+ t.libs.push "lib"
7
+ t.test_files = FileList['test/csv_record/*_test.rb']
8
+ t.verbose = true
9
+ end
10
+
11
+ desc "Run tests"
12
+ task :default => :test
@@ -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,11 @@
1
+ class Object
2
+ def integer?
3
+ self.to_s =~ /^\d+$/
4
+ !$0.empty?
5
+ end
6
+
7
+ def float?
8
+ self.to_s =~ /^\d+\.\d+$/
9
+ !$0.empty?
10
+ end
11
+ 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,3 @@
1
+ module CsvRecord
2
+ VERSION = "1.0.0"
3
+ 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,8 @@
1
+ require_relative '../test_helper'
2
+
3
+ require 'csv_record'
4
+
5
+ require_relative '../models/car'
6
+
7
+ describe CsvRecord do
8
+ end
@@ -0,0 +1,6 @@
1
+ require_relative '../test_helper'
2
+
3
+ require_relative '../models/car'
4
+
5
+ describe CsvRecord::Document do
6
+ end
@@ -0,0 +1,12 @@
1
+ require_relative '../test_helper'
2
+
3
+ describe 'CsvRecord::Helpers' do
4
+
5
+ it 'check if a string is an integer' do
6
+ '2000'.integer?.must_equal true
7
+ end
8
+
9
+ it 'check if a string is a float' do
10
+ '2000.00'.float?.must_equal true
11
+ end
12
+ 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
@@ -0,0 +1,13 @@
1
+ require 'csv_record'
2
+
3
+ class Car
4
+ include CsvRecord::Document
5
+
6
+ def initialize(params={})
7
+ params.each do |key, value|
8
+ self.public_send("#{key}=", value)
9
+ end
10
+ end
11
+
12
+ attr_accessor :year, :make, :model, :description, :price
13
+ end
@@ -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