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