virgola 0.0.2 → 0.0.3

Sign up to get free protection for your applications and to get access to all the features.
@@ -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
- gem install virgola
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
- def initialize
35
- yield self if block_given?
36
- end
37
+ after_map :do_something_after_mapping_a_row
37
38
 
38
- after_map :do_something_after_map_a_row
39
+ protected
39
40
 
40
- def ==(pip)
41
- return false unless pip.is_a?(Person)
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
- protected
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
- def do_something_after_map_a_row
48
- puts 'yes, victory!'
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 parse and map the file with the initial Extraction API:
74
+ You can access the mappings also as instance attributes.
54
75
 
55
76
  <pre lang="ruby">
56
- Person.parse(csv_contents).all # Array of Person instances mapping the guys above
57
- Person.parse(csv_contents).count # 3
58
- Person.parse(csv_contents).each { |pip| # do stuff }
59
- Person.parse(csv_contents).in_groups_of(100) { |pips| # do stuff }
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>
@@ -4,6 +4,7 @@ require 'active_model'
4
4
  require 'active_support/all'
5
5
 
6
6
  require 'virgola/version'
7
+ require 'virgola/attribute'
7
8
  require 'virgola/attribute_methods'
8
9
  require 'virgola/extraction_methods'
9
10
  require 'virgola/csv_parser'
@@ -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
 
@@ -5,7 +5,7 @@ require 'csv'
5
5
  module Virgola
6
6
  class CSVParser
7
7
  def initialize(klass, contents)
8
- @klass = 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
- mapped_object.send("#{attr.name}=", values[index])
21
+ attr.map(mapped_object, values[index])
22
22
  end
23
23
  mapped_object.run_callbacks(:map)
24
24
  mapped_object
@@ -1,3 +1,3 @@
1
1
  module Virgola
2
- VERSION = "0.0.2"
2
+ VERSION = "0.0.3"
3
3
  end
@@ -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
@@ -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
@@ -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 Ruby objects mapper.'
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.2
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-14 00:00:00.000000000 Z
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: &70302046764000 !ruby/object:Gem::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: *70302046764000
24
+ version_requirements: *70255741873540
25
25
  - !ruby/object:Gem::Dependency
26
26
  name: activemodel
27
- requirement: &70302046763500 !ruby/object:Gem::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: *70302046763500
35
+ version_requirements: *70255741872780
36
36
  - !ruby/object:Gem::Dependency
37
37
  name: bundler
38
- requirement: &70302046763000 !ruby/object:Gem::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: *70302046763000
47
- description: Virgola is a CSV to Ruby objects mapper.
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