virgola 0.0.2 → 0.0.3
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/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
|