active_csv 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,2 @@
1
+ *.gem
2
+ *todolist.txt
data/README ADDED
File without changes
@@ -0,0 +1,13 @@
1
+ Gem::Specification.new do |s|
2
+ s.name = 'active_csv'
3
+ s.version = '0.1.0'
4
+ s.add_dependency('activemodel', '>= 3.0.0')
5
+ s.summary = 'Inteds to allow you to work with csv data files with an API ActiveRecord-like'
6
+ s.description = 'Inteds to allow you to work with csv data files with an API ActiveRecord-like'
7
+ s.files = `git ls-files`.split("\n")
8
+ s.platform = Gem::Platform::RUBY
9
+ s.authors = ["Marco Antonio Fogaça Nogueira"]
10
+ s.required_rubygems_version = Gem::Requirement.new(">= 1.3.7")
11
+ s.email = ["marcofognog@gmail.com"]
12
+ s.require_paths = ["lib"]
13
+ end
data/init.rb ADDED
@@ -0,0 +1,2 @@
1
+ $: << File.expand_path("lib")
2
+ require 'active_csv'
@@ -0,0 +1,125 @@
1
+ require 'active_csv/errors'
2
+ require 'active_csv/class_methods'
3
+ require 'active_csv/attr_file'
4
+ require 'active_csv/db_file'
5
+ require 'rubygems'
6
+ require 'active_model'
7
+
8
+ class ActiveCSV
9
+ require 'csv'
10
+ require 'yaml'
11
+
12
+ extend ClassMethods
13
+ extend ActiveModel::Naming
14
+ include ActiveModel::Validations
15
+ include ActiveModel::Conversion
16
+
17
+ attr_accessor :id, :attr_file, :db_file
18
+
19
+ def initialize(*attributes)
20
+ if attributes[0].is_a? Hash || attributes[0].is_a?(ActiveSupport::HashWithIndifferentAccess)
21
+ hash_to_obj(attributes[0])
22
+ end
23
+ self.attr_file = AttrFile.new("config/csv_attributes.yml")
24
+ self.db_file = DbFile.new("db/"+model_name+".csv")
25
+ end
26
+
27
+ def model_name
28
+ self.class.to_s.downcase
29
+ end
30
+
31
+ def field_values
32
+ attributes = Array.new
33
+ attr_file.fields(model_name).each do |field|
34
+ attributes << eval(field)
35
+ end
36
+ attributes #String
37
+ end
38
+
39
+ def last_id
40
+ attr_array = self.db_file.csv_content
41
+ unless attr_array.count == 0
42
+ attr_array.last[0]
43
+ else
44
+ 0
45
+ end
46
+ end
47
+
48
+ def next_id
49
+ last_id.to_i+1
50
+ end
51
+
52
+ def persist_existing
53
+ destroy
54
+ persist_new_obj
55
+ end
56
+
57
+ def persist_new_obj
58
+ a = db_file.csv_content
59
+ new_row = field_values
60
+ CSV.open(db_file.name,"wb") do |csv|
61
+ a.each do |line|
62
+ csv << line
63
+ end
64
+ csv << new_row
65
+ end
66
+ end
67
+
68
+ # Also used by form_for in the views on Rails
69
+ def persisted?
70
+ unless self.id.nil?
71
+ true
72
+ else
73
+ false
74
+ end
75
+ end
76
+
77
+ def save
78
+ if valid?
79
+ unless persisted?
80
+ self.id = next_id
81
+ end
82
+ persist_existing
83
+ return true
84
+ else
85
+ return false
86
+ end
87
+ end
88
+
89
+ def destroy
90
+ csv_rows = db_file.csv_content
91
+ target_index = ''
92
+ unless self.id.nil?
93
+ ids = [self.id]
94
+ target_index = ActiveCSV.find_with_ids(ids,csv_rows).first
95
+ unless target_index.nil?
96
+ csv_rows.delete_at(target_index)
97
+ CSV.open(db_file.name,"wb") do |csv|
98
+ csv_rows.each do |line|
99
+ csv << line
100
+ end
101
+ end
102
+ else
103
+ return false
104
+ end
105
+ end
106
+ self
107
+ end
108
+
109
+ def hash_to_obj(hash)
110
+ hash.each do |key, value|
111
+ key = key.to_s
112
+ send("#{key}=", value)
113
+ end
114
+ end
115
+
116
+ def update_attributes(hash_attr)
117
+ hash_to_obj(hash_attr)
118
+ if valid?
119
+ persist_existing
120
+ true
121
+ else
122
+ false
123
+ end
124
+ end
125
+ end
@@ -0,0 +1,12 @@
1
+ class AttrFile
2
+ attr_accessor :name
3
+
4
+ def initialize(_name)
5
+ @name = _name
6
+ end
7
+ def fields(model_name)
8
+ # The sequency of the attributes is always the same as in the yaml file.
9
+ model_fields = YAML.load_file(@name)
10
+ model_fields[model_name].split(', ') #Array
11
+ end
12
+ end
@@ -0,0 +1,103 @@
1
+ module ClassMethods
2
+ def all
3
+ objects = Array.new
4
+ db_file = DbFile.new("db/"+model_name_+".csv")
5
+ attr_array = db_file.csv_content
6
+ objects = ar_to_obj(attr_array)
7
+ objects
8
+ end
9
+
10
+ def ar_to_obj(attr_array) # turns array of arrays into array of objects
11
+ objects = Array.new
12
+ attr_array.each do |row|
13
+ new_object = eval(self.name).new
14
+ fields_ar = new_object.attr_file.fields(model_name_)
15
+ fields_ar.each_index do |index|
16
+ new_object.send("#{fields_ar[index]}=",row[index])
17
+ end
18
+ objects << new_object
19
+ end
20
+ objects
21
+ end
22
+
23
+ #------- relacionadas ao find-----------
24
+ def check_attr?(attribute)
25
+ attr_file = AttrFile.new("config/csv_attributes.yml")
26
+ attr_file.fields(model_name_).include? attribute
27
+ end
28
+
29
+ def attr_column(attribute)
30
+ object = eval(self.name).new
31
+ object.attr_file.fields(model_name_).index attribute
32
+ end
33
+
34
+ def find_rows_by_indexes(indexes,content)
35
+ found_rows = Array.new
36
+ case indexes.size
37
+ when 0
38
+ raise RecordNotFound, "Couldn't find the especified ID"
39
+ else
40
+ indexes.each do |found|
41
+ found_rows << content[found]
42
+ end
43
+ end
44
+ found_rows
45
+ end
46
+
47
+ def find_with_ids(ids,content)
48
+ found_ids = Array.new
49
+ content.each_with_index do |row, index|
50
+ ids.each do |id|
51
+ if row[0] == id.to_s
52
+ found_ids << index
53
+ end
54
+ end
55
+ end
56
+ found_ids
57
+ end
58
+
59
+ def find_with_attr(attribute,value,content)
60
+ found_cols = Array.new
61
+ col = attr_column attribute.to_s
62
+ content.each_with_index do |row, index|
63
+ if row[col] == value
64
+ found_cols << index
65
+ end
66
+ end
67
+ found_cols #indexes
68
+ end
69
+
70
+ def find(*args)
71
+ file = DbFile.new("db/"+model_name_+".csv")
72
+ content = file.csv_content
73
+ if args[0].respond_to? "to_i"
74
+ ids = Array.new
75
+ args.each do |el|
76
+ ids << el.to_i
77
+ end
78
+ found_ids_indexes = find_with_ids(ids,content)
79
+ found_rows = find_rows_by_indexes(found_ids_indexes,content)
80
+ else
81
+ args[0].keys.each do |key|
82
+ if check_attr? key.to_s
83
+ found_rows_indexes = find_with_attr(key,args[0][key],content)
84
+ found_rows = find_rows_by_indexes(found_rows_indexes,content)
85
+ else
86
+ # raise error
87
+ end
88
+ end
89
+ end
90
+ found = ar_to_obj(found_rows)
91
+ if args.length == 1 && args[0].respond_to?("to_i")
92
+ return found.first
93
+ else
94
+ return found
95
+ end
96
+ end
97
+
98
+ #CAREFULL HERE
99
+ #use the method with the same name in ActiveModel::Naming
100
+ def model_name_
101
+ self.name.to_s.downcase
102
+ end
103
+ end
@@ -0,0 +1,29 @@
1
+ class DbFile
2
+ attr_accessor :name
3
+
4
+ def initialize(_name)
5
+ @name = _name
6
+ end
7
+ def csv_content
8
+ csv_rows = Array.new
9
+ if !file_exists?
10
+ create_db_file
11
+ end
12
+ CSV.read(name).each do |row|
13
+ csv_rows << row
14
+ end
15
+ csv_rows
16
+ end
17
+
18
+ def file_exists?
19
+ File.exists?(name)
20
+ end
21
+
22
+ def create_db_file
23
+ CSV.open(name,'w')
24
+ end
25
+
26
+ def field_values
27
+ ActiveCSV.field_values
28
+ end
29
+ end
@@ -0,0 +1,2 @@
1
+ class RecordNotFound < StandardError
2
+ end
@@ -0,0 +1,11 @@
1
+ require 'rake/testtask'
2
+
3
+ task :default => [:test_unit]
4
+
5
+ desc "Run basic tests"
6
+ Rake::TestTask.new("test_unit") do |t|
7
+ t.libs << ["../lib"]
8
+ t.test_files = FileList['test*.rb']
9
+ t.verbose = true
10
+ t.warning = true
11
+ end
@@ -0,0 +1,6 @@
1
+ require 'active_csv'
2
+
3
+ class Car < ActiveCSV
4
+ attr_accessor :color, :year, :brand
5
+ validates_presence_of :brand
6
+ end
@@ -0,0 +1,12 @@
1
+ expense:
2
+ id,
3
+ value,
4
+ description,
5
+ date,
6
+ mean
7
+
8
+ car:
9
+ id,
10
+ year,
11
+ color,
12
+ brand
@@ -0,0 +1,19 @@
1
+ require 'csv'
2
+
3
+ module TestHelpers
4
+ def create_sample_file
5
+ content = [["1","1997", "red","Fiat"],
6
+ ["2","1992", "red","Fiat"],
7
+ ["3","1964","yellow","Fusca"],
8
+ ["4","2012", "black","Citroën"]]
9
+ CSV.open("db/car.csv","wb") do |csv|
10
+ content.each do |line|
11
+ csv << line
12
+ end
13
+ end
14
+ end
15
+
16
+ def delete_sample
17
+ File.delete("db/car.csv")
18
+ end
19
+ end
@@ -0,0 +1,26 @@
1
+ require 'test/unit'
2
+ require 'test_helpers'
3
+ require 'car'
4
+
5
+ class AllTests < Test::Unit::TestCase
6
+ include TestHelpers
7
+
8
+ def test_all
9
+ create_sample_file
10
+ cars = Car.all
11
+ assert_equal(4,cars.length)
12
+ delete_sample
13
+ end
14
+
15
+ def test_kind_of_objects_from_all
16
+ create_sample_file
17
+ cars = Car.all
18
+ assert_instance_of Car, cars.first
19
+ delete_sample
20
+ end
21
+
22
+ def test_all_empty
23
+ cars = Car.all
24
+ assert_equal(0,cars.length)
25
+ end
26
+ end
@@ -0,0 +1,53 @@
1
+ require 'test/unit'
2
+ require 'test_helpers'
3
+ require 'car'
4
+
5
+ class DestroyTests < Test::Unit::TestCase
6
+ include TestHelpers
7
+
8
+ def test_destroy_when_exists
9
+ create_sample_file
10
+ car = Car.find(2)
11
+ car.destroy
12
+ assert_raise RecordNotFound do
13
+ Car.find(2)
14
+ end
15
+ delete_sample
16
+ end
17
+
18
+ def test_destroy_sequencially
19
+ create_sample_file
20
+ car = Car.find(2)
21
+ car.destroy
22
+ car2 = Car.find(3)
23
+ car2.destroy
24
+ assert_raise RecordNotFound do
25
+ Car.find(2)
26
+ end
27
+ assert_raise RecordNotFound do
28
+ Car.find(3)
29
+ end
30
+ assert_equal "red",Car.find(1).color
31
+ assert_equal "2012",Car.find(4).year
32
+ delete_sample
33
+ end
34
+
35
+ def test_destroy_obj_without_id
36
+ create_sample_file
37
+ car = Car.new
38
+ assert_kind_of Car, car.destroy
39
+ assert_equal 4, Car.all.length
40
+ assert_equal "2", Car.find(2).id
41
+ delete_sample
42
+ end
43
+
44
+ def test_destroy_file_without_id
45
+ create_sample_file
46
+ car = Car.new
47
+ car.id = 5
48
+ assert !car.destroy
49
+ assert_equal 4, Car.all.length
50
+ assert_equal "2", Car.find(2).id
51
+ delete_sample
52
+ end
53
+ end
@@ -0,0 +1,66 @@
1
+ require 'test/unit'
2
+ require 'test_helpers'
3
+ require 'car'
4
+ require 'rubygems'
5
+ require 'active_support/hash_with_indifferent_access'
6
+
7
+ class FindTests < Test::Unit::TestCase
8
+ include TestHelpers
9
+
10
+ def test_find_by_attr
11
+ create_sample_file
12
+ cars = Car.find(:color=>"red")
13
+ assert_equal "red", cars.first.color
14
+ delete_sample
15
+ end
16
+
17
+ def test_find_by_attr_missing
18
+ create_sample_file
19
+ assert_raise(RecordNotFound) { cars = Car.find(:color=>"darkblue") }
20
+ delete_sample
21
+ end
22
+
23
+ def test_find_by_attr_quatity
24
+ create_sample_file
25
+ cars = Car.find(:color=>"red")
26
+ assert_equal 2, cars.length
27
+ delete_sample
28
+ end
29
+
30
+ def test_find_by_id_2
31
+ create_sample_file
32
+ car = Car.find(2)
33
+ assert_equal "2", car.id
34
+ delete_sample
35
+ end
36
+
37
+ def test_find_by_id_3
38
+ create_sample_file
39
+ car = Car.find(3)
40
+ assert_equal "3", car.id
41
+ delete_sample
42
+ end
43
+
44
+ def test_find_by_id_missing
45
+ create_sample_file
46
+ assert_raise(RecordNotFound) { cars = Car.find(5) }
47
+ delete_sample
48
+ end
49
+
50
+ def test_find_by_ids
51
+ create_sample_file
52
+ cars = Car.find(3,4)
53
+ assert_equal "4", cars[1].id
54
+ assert_equal "3", cars[0].id
55
+ delete_sample
56
+ end
57
+
58
+ def test_find_with_active_support_hash
59
+ create_sample_file
60
+ params = ActiveSupport::HashWithIndifferentAccess.new
61
+ params[:id] = "2"
62
+ car = Car.find(params[:id])
63
+ assert_equal "2", car.id
64
+ delete_sample
65
+ end
66
+ end
@@ -0,0 +1,43 @@
1
+ require 'test/unit'
2
+ require 'test_helpers'
3
+ require 'car'
4
+ require 'rubygems'
5
+ require 'active_support/hash_with_indifferent_access'
6
+
7
+ class InitializeTests < Test::Unit::TestCase
8
+ include TestHelpers
9
+
10
+ def test_initialize_with_attr_hash
11
+ car = Car.new(:color=>"blues")
12
+ assert_equal "blues",car.color
13
+ end
14
+
15
+ def test_initialize_with_attr_hash
16
+ car = Car.new(:color=>"green")
17
+ assert_equal "green",car.color
18
+ end
19
+
20
+ def test_initialize_with_attr_symbol
21
+ car = Car.new(:color=>"darkblue", :year=>"1999",:brand=>"Renault")
22
+ assert_equal "darkblue",car.color
23
+ assert_equal "Renault",car.brand
24
+ assert_equal "1999",car.year
25
+ end
26
+
27
+ def test_initialize_with_attr_strings
28
+ car = Car.new("color"=>"darkblue", "year"=>"1999","brand"=>"Renault")
29
+ assert car.save
30
+ assert_equal "darkblue",car.color
31
+ assert_equal "Renault",car.brand
32
+ assert_equal "1999",car.year
33
+ end
34
+
35
+ def test_initialize_with_active_suport_hash
36
+ params = ActiveSupport::HashWithIndifferentAccess.new
37
+ params[:car] = {:color=>"blue", :year=>"1999", :brand=>"Gol"}
38
+ car = Car.new(params[:car])
39
+ assert_equal "Gol", car.brand
40
+ assert_equal "blue", car.color
41
+ assert_equal "1999", car.year
42
+ end
43
+ end
@@ -0,0 +1,15 @@
1
+ require 'test/unit'
2
+ require 'test_helpers'
3
+ require 'car'
4
+
5
+ class SaveTests < Test::Unit::TestCase
6
+ include TestHelpers
7
+
8
+ def test_persisted_is_still_false
9
+ create_sample_file
10
+ car = Car.new({:year=>"1999"})
11
+ assert !car.save #should return false and don't save, once Car validates_presence_of brand
12
+ assert !car.persisted?
13
+ delete_sample
14
+ end
15
+ end
@@ -0,0 +1,54 @@
1
+ require 'test/unit'
2
+ require 'test_helpers'
3
+ require 'car'
4
+
5
+ class SaveTests < Test::Unit::TestCase
6
+ include TestHelpers
7
+
8
+ def test_save_file_exists
9
+ car = Car.new
10
+ car.year = "1998"
11
+ car.color = "red"
12
+ car.brand = "wolksvagen"
13
+ car.save
14
+ assert File.exists? car.db_file.name
15
+ File.delete(car.db_file.name)
16
+ end
17
+
18
+ def test_save_quantity
19
+ create_sample_file
20
+ before = Car.all.length
21
+ car = Car.new
22
+ car.year = "1998"
23
+ car.color = "red"
24
+ car.brand = "wolksvagen"
25
+ assert car.save
26
+ assert_equal before+1, Car.all.length
27
+ delete_sample
28
+ end
29
+
30
+ def test_save_again
31
+ create_sample_file
32
+ before = Car.all.length
33
+ car = Car.new
34
+ car.year = "1998"
35
+ car.color = "red"
36
+ car.brand = "wolksvagen"
37
+ assert car.save
38
+ assert car.save
39
+ assert_equal before+1, Car.all.length
40
+ delete_sample
41
+ end
42
+
43
+ def test_dont_save_if_not_valid
44
+ create_sample_file
45
+ before = Car.all.length
46
+ car = Car.new
47
+ car.year = "1998"
48
+ car.color = "red"
49
+ assert !car.save
50
+ assert_equal before, Car.all.length
51
+ delete_sample
52
+ end
53
+
54
+ end
@@ -0,0 +1,66 @@
1
+ require 'test/unit'
2
+ require 'test_helpers'
3
+ require 'car'
4
+ require 'rubygems'
5
+ require 'active_support/hash_with_indifferent_access'
6
+
7
+ class UpdateAttributesTests < Test::Unit::TestCase
8
+ include TestHelpers
9
+
10
+ def test_update_attr_three_attr
11
+ create_sample_file
12
+ car = Car.find(1)
13
+ car.update_attributes({:year=>"2000",:color=>"yeallow", :brand=>"Fusquinha sem vergonha"})
14
+
15
+ assert_equal "yeallow",car.color
16
+ assert_equal "yeallow", Car.find(1).color
17
+ assert_equal "2000", Car.find(1).year
18
+ assert_equal "Fusquinha sem vergonha", Car.find(1).brand
19
+ delete_sample
20
+ end
21
+
22
+ def test_update_attr_two_attr
23
+ create_sample_file
24
+ car = Car.find(2)
25
+ car.update_attributes({:color=>"pink", :brand=>"Ferrari"})
26
+
27
+ assert_equal "pink",car.color
28
+ assert_equal "pink",Car.find(2).color
29
+ assert_equal "Ferrari",Car.find(2).brand
30
+ delete_sample
31
+ end
32
+
33
+ def test_update_attr_keeping_other_attr
34
+ create_sample_file
35
+ car = Car.find(2)
36
+ car.update_attributes({:brand=>"Gol bolinha"})
37
+
38
+ assert_equal "red",car.color
39
+ assert_equal "Gol bolinha",Car.find(2).brand
40
+ delete_sample
41
+ end
42
+
43
+ def test_update_attributes_with_as_hash
44
+ create_sample_file
45
+ params = ActiveSupport::HashWithIndifferentAccess.new
46
+ params[:car] = {:color => "blue", :year => "2000", :brand => "Gol"}
47
+ car = Car.find(2)
48
+ car.update_attributes(params[:car])
49
+ assert_equal "blue", Car.find(2).color
50
+ assert_equal "2000", Car.find(2).year
51
+ assert_equal "Gol", Car.find(2).brand
52
+ delete_sample
53
+ end
54
+
55
+ def test_dont_update_attributes_if_not_valid
56
+ create_sample_file
57
+ params = ActiveSupport::HashWithIndifferentAccess.new
58
+ params[:car] = {:color => "blue", :year => "2000", :brand=>""}
59
+ car = Car.find(2)
60
+ assert !car.update_attributes(params[:car])
61
+ assert_not_equal "blue", Car.find(2).color
62
+ assert_not_equal "2000", Car.find(2).year
63
+
64
+ delete_sample
65
+ end
66
+ end
metadata ADDED
@@ -0,0 +1,104 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: active_csv
3
+ version: !ruby/object:Gem::Version
4
+ hash: 27
5
+ prerelease:
6
+ segments:
7
+ - 0
8
+ - 1
9
+ - 0
10
+ version: 0.1.0
11
+ platform: ruby
12
+ authors:
13
+ - "Marco Antonio Foga\xC3\xA7a Nogueira"
14
+ autorequire:
15
+ bindir: bin
16
+ cert_chain: []
17
+
18
+ date: 2011-03-09 00:00:00 -03:00
19
+ default_executable:
20
+ dependencies:
21
+ - !ruby/object:Gem::Dependency
22
+ name: activemodel
23
+ prerelease: false
24
+ requirement: &id001 !ruby/object:Gem::Requirement
25
+ none: false
26
+ requirements:
27
+ - - ">="
28
+ - !ruby/object:Gem::Version
29
+ hash: 7
30
+ segments:
31
+ - 3
32
+ - 0
33
+ - 0
34
+ version: 3.0.0
35
+ type: :runtime
36
+ version_requirements: *id001
37
+ description: Inteds to allow you to work with csv data files with an API ActiveRecord-like
38
+ email:
39
+ - marcofognog@gmail.com
40
+ executables: []
41
+
42
+ extensions: []
43
+
44
+ extra_rdoc_files: []
45
+
46
+ files:
47
+ - .gitignore
48
+ - README
49
+ - active_csv.gemspec
50
+ - init.rb
51
+ - lib/active_csv.rb
52
+ - lib/active_csv/attr_file.rb
53
+ - lib/active_csv/class_methods.rb
54
+ - lib/active_csv/db_file.rb
55
+ - lib/active_csv/errors.rb
56
+ - tests/Rakefile
57
+ - tests/car.rb
58
+ - tests/config/csv_attributes.yml
59
+ - tests/test_helpers.rb
60
+ - tests/tests_all.rb
61
+ - tests/tests_destroy.rb
62
+ - tests/tests_find.rb
63
+ - tests/tests_initialize.rb
64
+ - tests/tests_persisted.rb
65
+ - tests/tests_save.rb
66
+ - tests/tests_update_attributes.rb
67
+ has_rdoc: true
68
+ homepage:
69
+ licenses: []
70
+
71
+ post_install_message:
72
+ rdoc_options: []
73
+
74
+ require_paths:
75
+ - lib
76
+ required_ruby_version: !ruby/object:Gem::Requirement
77
+ none: false
78
+ requirements:
79
+ - - ">="
80
+ - !ruby/object:Gem::Version
81
+ hash: 3
82
+ segments:
83
+ - 0
84
+ version: "0"
85
+ required_rubygems_version: !ruby/object:Gem::Requirement
86
+ none: false
87
+ requirements:
88
+ - - ">="
89
+ - !ruby/object:Gem::Version
90
+ hash: 21
91
+ segments:
92
+ - 1
93
+ - 3
94
+ - 7
95
+ version: 1.3.7
96
+ requirements: []
97
+
98
+ rubyforge_project:
99
+ rubygems_version: 1.6.1
100
+ signing_key:
101
+ specification_version: 3
102
+ summary: Inteds to allow you to work with csv data files with an API ActiveRecord-like
103
+ test_files: []
104
+