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 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