virgola 0.0.2 → 0.0.3
Sign up to get free protection for your applications and to get access to all the features.
- data/README.textile +43 -17
- data/lib/virgola.rb +1 -0
- data/lib/virgola/attribute.rb +57 -0
- data/lib/virgola/attribute_methods.rb +1 -18
- data/lib/virgola/csv_parser.rb +2 -2
- data/lib/virgola/version.rb +1 -1
- data/spec/virgola_attribute_type_castings.rb +75 -0
- data/spec/virgola_spec.rb +20 -0
- data/virgola.gemspec +1 -1
- metadata +12 -9
data/README.textile
CHANGED
@@ -3,12 +3,15 @@ h1. virgola
|
|
3
3
|
CSV to object mapping library.
|
4
4
|
|
5
5
|
h2. Author
|
6
|
+
|
6
7
|
"Vicente Reig Rincón de Arellano":http://twitter.com/vicentereig
|
7
8
|
|
8
9
|
|
9
10
|
h2. Installation
|
10
11
|
|
11
|
-
|
12
|
+
<pre lang="bash">
|
13
|
+
$ gem install virgola
|
14
|
+
</pre>
|
12
15
|
|
13
16
|
h2. Usage
|
14
17
|
|
@@ -21,7 +24,7 @@ Given the following CSV file
|
|
21
24
|
3,"Vicente Reig",vicente@propertybase.com
|
22
25
|
</pre>
|
23
26
|
|
24
|
-
You map it to an array of Person objects.
|
27
|
+
You map it to an array of Person objects by specifying to match columns with the `attribute` method.
|
25
28
|
|
26
29
|
<pre lang="ruby">
|
27
30
|
class Person
|
@@ -31,30 +34,53 @@ You map it to an array of Person objects.
|
|
31
34
|
attribute :name
|
32
35
|
attribute :email
|
33
36
|
|
34
|
-
|
35
|
-
yield self if block_given?
|
36
|
-
end
|
37
|
+
after_map :do_something_after_mapping_a_row
|
37
38
|
|
38
|
-
|
39
|
+
protected
|
39
40
|
|
40
|
-
def
|
41
|
-
|
42
|
-
self.id == pip.id && self.name == pip.name && self.email == pip.email
|
41
|
+
def do_something_after_mapping_a_row
|
42
|
+
puts 'YES, victory!'
|
43
43
|
end
|
44
|
+
end
|
45
|
+
</pre>
|
44
46
|
|
45
|
-
|
47
|
+
You actually extract the data and perform the mappings using the Extraction API.
|
48
|
+
|
49
|
+
<pre lang="ruby">
|
50
|
+
Person.parse(csv).all # Array of Person instances mapping the guys above
|
51
|
+
Person.parse(csv).count # 3
|
52
|
+
Person.parse(csv).each { |pip|
|
53
|
+
# do stuff
|
54
|
+
}
|
55
|
+
Person.parse(csv).in_groups_of(100) { |pips|
|
56
|
+
# do stuff
|
57
|
+
}
|
58
|
+
</pre>
|
46
59
|
|
47
|
-
|
48
|
-
|
60
|
+
Attributes are overridable.
|
61
|
+
|
62
|
+
<pre lang="ruby">
|
63
|
+
class Person
|
64
|
+
def email
|
65
|
+
"<#{super}>"
|
49
66
|
end
|
50
67
|
end
|
68
|
+
|
69
|
+
Person.parse(csv).each do |pip|
|
70
|
+
puts pip.email # <chris@propertybase.com>, ...
|
71
|
+
end
|
51
72
|
</pre>
|
52
73
|
|
53
|
-
You can
|
74
|
+
You can access the mappings also as instance attributes.
|
54
75
|
|
55
76
|
<pre lang="ruby">
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
77
|
+
class Person
|
78
|
+
def email
|
79
|
+
"<#{@email}>"
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
Person.parse(csv).each do |pip|
|
84
|
+
puts pip.email # <chris@propertybase.com>, ...
|
85
|
+
end
|
60
86
|
</pre>
|
data/lib/virgola.rb
CHANGED
@@ -0,0 +1,57 @@
|
|
1
|
+
class Boolean; end
|
2
|
+
|
3
|
+
module Virgola
|
4
|
+
|
5
|
+
Types = [String, Float, Time, Date, DateTime, Integer, Boolean]
|
6
|
+
|
7
|
+
|
8
|
+
class Attribute
|
9
|
+
attr_accessor :name, :type, :options
|
10
|
+
|
11
|
+
def initialize(name,type=String,*args)
|
12
|
+
@name = name
|
13
|
+
@type = type
|
14
|
+
@value = nil
|
15
|
+
@options = args.extract_options!
|
16
|
+
end
|
17
|
+
|
18
|
+
def map(mapped_object, value)
|
19
|
+
mapped_object.send("#{self.name}=", cast(value))
|
20
|
+
end
|
21
|
+
|
22
|
+
#
|
23
|
+
# Based on <https://github.com/jnunemaker/happymapper/blob/master/lib/happymapper/item.rb#L84>
|
24
|
+
#
|
25
|
+
def cast(value)
|
26
|
+
if self.type == Float then value.to_f
|
27
|
+
elsif self.type == Time then Time.parse(value)
|
28
|
+
elsif self.type == Date then Date.parse(value)
|
29
|
+
elsif self.type == DateTime then DateTime.parse(value)
|
30
|
+
elsif self.type == Boolean then ['true', 't'].include?(value.to_s.downcase)
|
31
|
+
elsif self.type == Integer then
|
32
|
+
# ganked from happymapper :)
|
33
|
+
value_to_i = value.to_i
|
34
|
+
if value_to_i == 0 && value != '0'
|
35
|
+
value_to_s = value.to_s
|
36
|
+
begin
|
37
|
+
Integer(value_to_s =~ /^(\d+)/ ? $1 : value_to_s)
|
38
|
+
rescue ArgumentError
|
39
|
+
nil
|
40
|
+
end
|
41
|
+
else
|
42
|
+
value_to_i
|
43
|
+
end
|
44
|
+
else
|
45
|
+
value
|
46
|
+
end
|
47
|
+
rescue
|
48
|
+
value
|
49
|
+
end
|
50
|
+
|
51
|
+
def ==(attribute)
|
52
|
+
return false unless attribute.is_a?(Attribute)
|
53
|
+
self.name == attribute.name
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
end
|
@@ -5,22 +5,6 @@
|
|
5
5
|
# http://railstips.org/blog/archives/2010/08/29/building-an-object-mapper-override-able-accessors/
|
6
6
|
#
|
7
7
|
module Virgola
|
8
|
-
|
9
|
-
class Attribute
|
10
|
-
attr_accessor :name, :options, :value
|
11
|
-
|
12
|
-
def initialize(name,*args)
|
13
|
-
@name = name
|
14
|
-
@value = nil
|
15
|
-
@options = args.extract_options!
|
16
|
-
end
|
17
|
-
|
18
|
-
def ==(attribute)
|
19
|
-
return false unless attribute.is_a?(Attribute)
|
20
|
-
self.name == attribute.name && self.value == attribute.value
|
21
|
-
end
|
22
|
-
end
|
23
|
-
|
24
8
|
module AttributeMethods
|
25
9
|
extend ActiveSupport::Concern
|
26
10
|
include ActiveModel::AttributeMethods
|
@@ -36,7 +20,7 @@ module Virgola
|
|
36
20
|
|
37
21
|
def attribute(name, options={})
|
38
22
|
define_attribute_methods Array.wrap name
|
39
|
-
attribute = Attribute.new(name.to_sym, options)
|
23
|
+
attribute = Attribute.new(name.to_sym, options.delete(:type), options)
|
40
24
|
attributes << attribute unless attributes.include?(attribute)
|
41
25
|
end
|
42
26
|
end
|
@@ -50,7 +34,6 @@ module Virgola
|
|
50
34
|
end
|
51
35
|
|
52
36
|
def attribute?(name)
|
53
|
-
binding.pry
|
54
37
|
self.attribute(name).present?
|
55
38
|
end
|
56
39
|
|
data/lib/virgola/csv_parser.rb
CHANGED
@@ -5,7 +5,7 @@ require 'csv'
|
|
5
5
|
module Virgola
|
6
6
|
class CSVParser
|
7
7
|
def initialize(klass, contents)
|
8
|
-
@klass
|
8
|
+
@klass = klass
|
9
9
|
@contents = contents
|
10
10
|
end
|
11
11
|
|
@@ -18,7 +18,7 @@ module Virgola
|
|
18
18
|
mapped_object = @klass.new
|
19
19
|
|
20
20
|
@klass.attributes.each.with_index do |attr, index|
|
21
|
-
|
21
|
+
attr.map(mapped_object, values[index])
|
22
22
|
end
|
23
23
|
mapped_object.run_callbacks(:map)
|
24
24
|
mapped_object
|
data/lib/virgola/version.rb
CHANGED
@@ -0,0 +1,75 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
class PersonWithoutCasting
|
4
|
+
include Virgola
|
5
|
+
|
6
|
+
attribute :id # defaults to String
|
7
|
+
attribute :name # defaults to String
|
8
|
+
attribute :email # defaults to String
|
9
|
+
|
10
|
+
def initialize
|
11
|
+
yield self if block_given?
|
12
|
+
end
|
13
|
+
|
14
|
+
after_map :do_something_after_map_a_row
|
15
|
+
|
16
|
+
def ==(pip)
|
17
|
+
return false unless pip.is_a?(Person)
|
18
|
+
self.id == pip.id && self.name == pip.name && self.email == pip.email
|
19
|
+
end
|
20
|
+
|
21
|
+
protected
|
22
|
+
|
23
|
+
def do_something_after_map_a_row
|
24
|
+
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
class Person
|
29
|
+
include Virgola
|
30
|
+
|
31
|
+
attribute :id, type: Integer
|
32
|
+
attribute :name, type: String # although it defaults to String
|
33
|
+
attribute :email, type: String
|
34
|
+
|
35
|
+
def initialize
|
36
|
+
yield self if block_given?
|
37
|
+
end
|
38
|
+
|
39
|
+
after_map :do_something_after_map_a_row
|
40
|
+
|
41
|
+
def ==(pip)
|
42
|
+
return false unless pip.is_a?(Person)
|
43
|
+
self.id == pip.id && self.name == pip.name && self.email == pip.email
|
44
|
+
end
|
45
|
+
|
46
|
+
protected
|
47
|
+
|
48
|
+
def do_something_after_map_a_row
|
49
|
+
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
CSV_INPUT = <<-CSV
|
54
|
+
id,name,email
|
55
|
+
1,"Chris Floess",chris@propertybase.com
|
56
|
+
2,"Konstantin Krauss",konstantin@propertybase.com
|
57
|
+
3,"Vicente Reig",vicente@propertybase.com
|
58
|
+
CSV
|
59
|
+
|
60
|
+
describe Virgola::Attribute do
|
61
|
+
|
62
|
+
before :each do
|
63
|
+
@person_parser = Person.parse(CSV_INPUT)
|
64
|
+
@chris = Person.new { |p| p.id = 1; p.name = "Chris Floess"; p.email = "chris@propertybase.com"}
|
65
|
+
@konsti = Person.new { |p| p.id = 2; p.name = "Konstantin Krauss"; p.email = "konstantin@propertybase.com"}
|
66
|
+
@vicente = Person.new { |p| p.id = 3; p.name = "Vicente Reig"; p.email = "vicente@propertybase.com"}
|
67
|
+
@expected_pips = [@chris, @konsti, @vicente]
|
68
|
+
end
|
69
|
+
|
70
|
+
it 'should match us' do
|
71
|
+
Person.parse(CSV_INPUT).all.should == @expected_pips
|
72
|
+
end
|
73
|
+
|
74
|
+
|
75
|
+
end
|
data/spec/virgola_spec.rb
CHANGED
@@ -64,4 +64,24 @@ describe Virgola do
|
|
64
64
|
@expected_pips.should include group.first
|
65
65
|
}
|
66
66
|
end
|
67
|
+
|
68
|
+
it 'should allow to override attribute accesors' do
|
69
|
+
class Person
|
70
|
+
def email
|
71
|
+
"<#{super}>"
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
@chris.email.should == "<chris@propertybase.com>"
|
76
|
+
end
|
77
|
+
|
78
|
+
it 'should allow to access instance attributes' do
|
79
|
+
class Person
|
80
|
+
def email
|
81
|
+
"<#{@email}>"
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
@chris.email.should == "<chris@propertybase.com>"
|
86
|
+
end
|
67
87
|
end
|
data/virgola.gemspec
CHANGED
@@ -7,7 +7,7 @@ Gem::Specification.new do |s|
|
|
7
7
|
s.name = 'virgola'
|
8
8
|
s.version = Virgola::VERSION
|
9
9
|
s.summary = 'An attempt to make CSV parsing and mapping suck less.'
|
10
|
-
s.description = 'Virgola is a CSV to
|
10
|
+
s.description = 'Virgola is a CSV to object mapper.'
|
11
11
|
s.files = Dir.glob("{lib,spec}/**/*") + %w[License Rakefile README.textile]
|
12
12
|
s.required_ruby_version = '>= 1.9.2'
|
13
13
|
s.required_rubygems_version = '>= 1.8.11'
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: virgola
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.3
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,11 +9,11 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2012-02-
|
12
|
+
date: 2012-02-17 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: activesupport
|
16
|
-
requirement: &
|
16
|
+
requirement: &70255741873540 !ruby/object:Gem::Requirement
|
17
17
|
none: false
|
18
18
|
requirements:
|
19
19
|
- - =
|
@@ -21,10 +21,10 @@ dependencies:
|
|
21
21
|
version: 3.1.3
|
22
22
|
type: :runtime
|
23
23
|
prerelease: false
|
24
|
-
version_requirements: *
|
24
|
+
version_requirements: *70255741873540
|
25
25
|
- !ruby/object:Gem::Dependency
|
26
26
|
name: activemodel
|
27
|
-
requirement: &
|
27
|
+
requirement: &70255741872780 !ruby/object:Gem::Requirement
|
28
28
|
none: false
|
29
29
|
requirements:
|
30
30
|
- - =
|
@@ -32,10 +32,10 @@ dependencies:
|
|
32
32
|
version: 3.1.3
|
33
33
|
type: :runtime
|
34
34
|
prerelease: false
|
35
|
-
version_requirements: *
|
35
|
+
version_requirements: *70255741872780
|
36
36
|
- !ruby/object:Gem::Dependency
|
37
37
|
name: bundler
|
38
|
-
requirement: &
|
38
|
+
requirement: &70255741872040 !ruby/object:Gem::Requirement
|
39
39
|
none: false
|
40
40
|
requirements:
|
41
41
|
- - ~>
|
@@ -43,8 +43,8 @@ dependencies:
|
|
43
43
|
version: '1.0'
|
44
44
|
type: :runtime
|
45
45
|
prerelease: false
|
46
|
-
version_requirements: *
|
47
|
-
description: Virgola is a CSV to
|
46
|
+
version_requirements: *70255741872040
|
47
|
+
description: Virgola is a CSV to object mapper.
|
48
48
|
email: vicente@propertybase.com
|
49
49
|
executables: []
|
50
50
|
extensions: []
|
@@ -58,6 +58,7 @@ files:
|
|
58
58
|
- README.textile
|
59
59
|
- Rakefile
|
60
60
|
- lib/virgola.rb
|
61
|
+
- lib/virgola/attribute.rb
|
61
62
|
- lib/virgola/attribute_methods.rb
|
62
63
|
- lib/virgola/callbacks.rb
|
63
64
|
- lib/virgola/csv_parser.rb
|
@@ -65,6 +66,7 @@ files:
|
|
65
66
|
- lib/virgola/version.rb
|
66
67
|
- spec/spec_helper.rb
|
67
68
|
- spec/virgola_attribute_methods_spec.rb
|
69
|
+
- spec/virgola_attribute_type_castings.rb
|
68
70
|
- spec/virgola_callbacks_spec.rb
|
69
71
|
- spec/virgola_spec.rb
|
70
72
|
- virgola.gemspec
|
@@ -95,5 +97,6 @@ summary: An attempt to make CSV parsing and mapping suck less.
|
|
95
97
|
test_files:
|
96
98
|
- spec/spec_helper.rb
|
97
99
|
- spec/virgola_attribute_methods_spec.rb
|
100
|
+
- spec/virgola_attribute_type_castings.rb
|
98
101
|
- spec/virgola_callbacks_spec.rb
|
99
102
|
- spec/virgola_spec.rb
|