virgola 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
data/.gitignore ADDED
@@ -0,0 +1,4 @@
1
+ *.gem
2
+ .bundle
3
+ Gemfile.lock
4
+ pkg/*
data/.rvmrc ADDED
@@ -0,0 +1,47 @@
1
+ #!/usr/bin/env bash
2
+
3
+ # This is an RVM Project .rvmrc file, used to automatically load the ruby
4
+ # development environment upon cd'ing into the directory
5
+
6
+ # First we specify our desired <ruby>[@<gemset>], the @gemset name is optional.
7
+ environment_id="ruby-1.9.3-p0@virgola"
8
+
9
+ #
10
+ # First we attempt to load the desired environment directly from the environment
11
+ # file. This is very fast and efficicent compared to running through the entire
12
+ # CLI and selector. If you want feedback on which environment was used then
13
+ # insert the word 'use' after --create as this triggers verbose mode.
14
+ #
15
+ if [[ -d "${rvm_path:-$HOME/.rvm}/environments" \
16
+ && -s "${rvm_path:-$HOME/.rvm}/environments/$environment_id" ]] ; then
17
+ \. "${rvm_path:-$HOME/.rvm}/environments/$environment_id"
18
+ else
19
+ # If the environment file has not yet been created, use the RVM CLI to select.
20
+ rvm --create "$environment_id"
21
+ fi
22
+
23
+ #
24
+ # If you use an RVM gemset file to install a list of gems (*.gems), you can have
25
+ # it be automatically loaded. Uncomment the following and adjust the filename if
26
+ # necessary.
27
+ #
28
+ # filename=".gems"
29
+ # if [[ -s "$filename" ]] ; then
30
+ # rvm gemset import "$filename" | grep -v already | grep -v listed | grep -v complete | sed '/^$/d'
31
+ # fi
32
+
33
+ #
34
+ # If you use bundler and would like to run bundle each time you enter the
35
+ # directory, you can uncomment the following code.
36
+ #
37
+ # # Ensure that Bundler is installed. Install it if it is not.
38
+ # if ! command -v bundle >/dev/null; then
39
+ # printf "The rubygem 'bundler' is not installed. Installing it now.\n"
40
+ # gem install bundler
41
+ # fi
42
+ #
43
+ # # Bundle while reducing excess noise.
44
+ # printf "Bundling your gems. This may take a few minutes on a fresh clone.\n"
45
+ # bundle | grep -v '^Using ' | grep -v ' is complete' | sed '/^$/d'
46
+ #
47
+
data/Gemfile ADDED
@@ -0,0 +1,9 @@
1
+ source 'https://rubygems.org'
2
+
3
+ gemspec
4
+
5
+ group :development do
6
+ gem 'rspec'
7
+ gem 'rake'
8
+ gem 'pry'
9
+ end
data/Gemfile.lock ADDED
@@ -0,0 +1,46 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ virgola (0.0.1)
5
+ activemodel (= 3.1.3)
6
+ activesupport (= 3.1.3)
7
+ bundler (~> 1.0)
8
+
9
+ GEM
10
+ remote: https://rubygems.org/
11
+ specs:
12
+ activemodel (3.1.3)
13
+ activesupport (= 3.1.3)
14
+ builder (~> 3.0.0)
15
+ i18n (~> 0.6)
16
+ activesupport (3.1.3)
17
+ multi_json (~> 1.0)
18
+ builder (3.0.0)
19
+ coderay (1.0.5)
20
+ diff-lcs (1.1.3)
21
+ i18n (0.6.0)
22
+ method_source (0.7.0)
23
+ multi_json (1.0.4)
24
+ pry (0.9.8.2)
25
+ coderay (~> 1.0.5)
26
+ method_source (~> 0.7)
27
+ slop (>= 2.4.4, < 3)
28
+ rake (0.9.2.2)
29
+ rspec (2.8.0)
30
+ rspec-core (~> 2.8.0)
31
+ rspec-expectations (~> 2.8.0)
32
+ rspec-mocks (~> 2.8.0)
33
+ rspec-core (2.8.0)
34
+ rspec-expectations (2.8.0)
35
+ diff-lcs (~> 1.1.2)
36
+ rspec-mocks (2.8.0)
37
+ slop (2.4.4)
38
+
39
+ PLATFORMS
40
+ ruby
41
+
42
+ DEPENDENCIES
43
+ pry
44
+ rake
45
+ rspec
46
+ virgola!
data/License ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2012 Vicente Reig Rincón de Arellano
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.rdoc ADDED
@@ -0,0 +1,46 @@
1
+ = virgola
2
+
3
+ CSV to object mapping library.
4
+
5
+ == Usage
6
+
7
+ Given the following CSV file
8
+
9
+ id,name,email
10
+ 1,"Chris Floess",chris@propertybase.com
11
+ 2,"Konstantin Krauss",konstantin@propertybase.com
12
+ 3,"Vicente Reig",vicente@propertybase.com
13
+
14
+ You map it to an array of Person objects.
15
+
16
+ class Person
17
+ include Virgola
18
+
19
+ attribute :id
20
+ attribute :name
21
+ attribute :email
22
+
23
+ def initialize
24
+ yield self if block_given?
25
+ end
26
+
27
+ after_map :do_something_after_map_a_row
28
+
29
+ def ==(pip)
30
+ return false unless pip.is_a?(Person)
31
+ self.id == pip.id && self.name == pip.name && self.email == pip.email
32
+ end
33
+
34
+ protected
35
+
36
+ def do_something_after_map_a_row
37
+ puts 'yes, victory!'
38
+ end
39
+ end
40
+
41
+ You can parse and map the file with the initial Extraction API:
42
+
43
+ Person.parse(csv_contents).all # Array of Person instances mapping the guys above
44
+ Person.parse(csv_contents).count # 3
45
+ Person.parse(csv_contents).each { |pip| # do stuff }
46
+ Person.parse(csv_contents).in_groups_of(100) { |pips| # do stuff }
data/Rakefile ADDED
@@ -0,0 +1 @@
1
+ require "bundler/gem_tasks"
@@ -0,0 +1,61 @@
1
+ # encoding: UTF-8
2
+
3
+ #
4
+ # Overridable accessors as of Nunemaker.
5
+ # http://railstips.org/blog/archives/2010/08/29/building-an-object-mapper-override-able-accessors/
6
+ #
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
+ module AttributeMethods
25
+ extend ActiveSupport::Concern
26
+ include ActiveModel::AttributeMethods
27
+
28
+ included do
29
+ attribute_method_suffix '', '=', '?'
30
+ end
31
+
32
+ module ClassMethods
33
+ def attributes
34
+ @attributes ||= []
35
+ end
36
+
37
+ def attribute(name, options={})
38
+ define_attribute_methods Array.wrap name
39
+ attribute = Attribute.new(name.to_sym, options)
40
+ attributes << attribute unless attributes.include?(attribute)
41
+ end
42
+ end
43
+
44
+ def attribute(name)
45
+ instance_variable_get "@#{name}"
46
+ end
47
+
48
+ def attribute=(name, value)
49
+ instance_variable_set "@#{name}", value
50
+ end
51
+
52
+ def attribute?(name)
53
+ binding.pry
54
+ self.attribute(name).present?
55
+ end
56
+
57
+ def attributes
58
+ self.class.attributes
59
+ end
60
+ end
61
+ end
@@ -0,0 +1,18 @@
1
+ # encoding: UTF-8
2
+ module Virgola
3
+ module Callbacks
4
+ extend ActiveSupport::Concern
5
+
6
+ # ActiveModel::Callbacks is just a Ruby module, not a ActiveSupport::Concern module.
7
+ included do
8
+ extend ActiveModel::Callbacks
9
+ include ActiveModel::Validations::Callbacks
10
+
11
+ define_model_callbacks :map, only: [:after]
12
+ end
13
+
14
+ module ClassMethods
15
+ include ActiveModel::Callbacks
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,27 @@
1
+ # encoding: UTF-8
2
+
3
+ require 'csv'
4
+
5
+ module Virgola
6
+ class CSVParser
7
+ def initialize(klass, contents)
8
+ @klass = klass
9
+ @contents = contents
10
+ end
11
+
12
+ def extract(csv)
13
+ result_set = CSV.parse(csv*"\n")
14
+ result_set.collect { |result_set_row| map(result_set_row) }
15
+ end
16
+
17
+ def map(values)
18
+ mapped_object = @klass.new
19
+
20
+ @klass.attributes.each.with_index do |attr, index|
21
+ mapped_object.send("#{attr.name}=", values[index])
22
+ end
23
+ mapped_object.run_callbacks(:map)
24
+ mapped_object
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,32 @@
1
+ # encoding: UTF-8
2
+ module Virgola::ExtractionMethods
3
+ extend ActiveSupport::Concern
4
+
5
+ def count
6
+ @contents.size-1
7
+ end
8
+
9
+ def all
10
+ self.in_groups_of(@contents.size)
11
+ end
12
+
13
+ def each
14
+ self.in_groups_of(1) { |group|
15
+ yield group.first
16
+ }
17
+ end
18
+
19
+ def in_groups_of(batch_size=1000)
20
+ all_groups = []
21
+
22
+ (0..self.count).step(batch_size) { |batch_start|
23
+ batch_offset = batch_start + batch_size
24
+ batch_offset = @contents.size if batch_offset >= @contents.size
25
+
26
+ group = self.extract(@contents[batch_start+1, batch_offset])
27
+ (block_given? && group.present?) ? (yield group) : (all_groups += group)
28
+ }
29
+
30
+ all_groups
31
+ end
32
+ end
@@ -0,0 +1,3 @@
1
+ module Virgola
2
+ VERSION = "0.0.1"
3
+ end
data/lib/virgola.rb ADDED
@@ -0,0 +1,27 @@
1
+ # encoding: UTF-8
2
+ # TODO: split them into smaller requires
3
+ require 'active_model'
4
+ require 'active_support/all'
5
+
6
+ require 'virgola/version'
7
+ require 'virgola/attribute_methods'
8
+ require 'virgola/extraction_methods'
9
+ require 'virgola/csv_parser'
10
+ require 'virgola/callbacks'
11
+
12
+ module Virgola
13
+ extend ActiveSupport::Concern
14
+
15
+ include Virgola::AttributeMethods
16
+ include Virgola::Callbacks
17
+
18
+ class CSVParser
19
+ include Virgola::ExtractionMethods
20
+ end
21
+
22
+ module ClassMethods
23
+ def parse(csv)
24
+ @parser = CSVParser.new self, csv.strip.split("\n")
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,5 @@
1
+ require 'rubygems'
2
+ require 'bundler/setup'
3
+
4
+ require 'rspec'
5
+ require File.expand_path('../../lib/virgola', __FILE__)
@@ -0,0 +1,21 @@
1
+ require 'spec_helper'
2
+
3
+ class Person
4
+ include Virgola::AttributeMethods
5
+
6
+ attribute :id, match: 'refno'
7
+ attribute :name, match: 'givenname'
8
+ end
9
+
10
+ describe Virgola do
11
+
12
+ before :all do
13
+ @person = Person.new
14
+ end
15
+
16
+ it 'should respond to the id method' do
17
+ @person.should respond_to :id
18
+ @person.should respond_to :name
19
+ end
20
+
21
+ end
@@ -0,0 +1,39 @@
1
+ require 'spec_helper'
2
+
3
+ module DummyMapper
4
+ extend ActiveSupport::Concern
5
+
6
+ module ClassMethods
7
+ def parse(csv)
8
+ true
9
+ end
10
+ end
11
+
12
+ def map
13
+ true
14
+ end
15
+ end
16
+
17
+ class Person
18
+ include Virgola::Callbacks, DummyMapper
19
+
20
+ after_map :do_something_after_map_a_row
21
+
22
+ protected
23
+
24
+ def do_something_after_map_a_row
25
+ true
26
+ end
27
+ end
28
+
29
+ describe Virgola do
30
+
31
+ before :all do
32
+ @person = Person.new
33
+ end
34
+
35
+ it 'should process callbacks after mapping' do
36
+ @person.should_receive :do_something_after_map_a_row
37
+ @person.run_callbacks(:map)
38
+ end
39
+ end
@@ -0,0 +1,67 @@
1
+ require 'spec_helper'
2
+
3
+ class Person
4
+ include Virgola
5
+
6
+ attribute :id
7
+ attribute :name
8
+ attribute :email
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
+ CSV_INPUT = <<-CSV
29
+ id,name,email
30
+ 1,"Chris Floess",chris@propertybase.com
31
+ 2,"Konstantin Krauss",konstantin@propertybase.com
32
+ 3,"Vicente Reig",vicente@propertybase.com
33
+ CSV
34
+
35
+ describe Virgola do
36
+
37
+ before :each do
38
+ @person_parser = Person.parse(CSV_INPUT)
39
+ @chris = Person.new { |p| p.id = "1"; p.name = "Chris Floess"; p.email = "chris@propertybase.com"}
40
+ @konsti = Person.new { |p| p.id = "2"; p.name = "Konstantin Krauss"; p.email = "konstantin@propertybase.com"}
41
+ @vicente = Person.new { |p| p.id = "3"; p.name = "Vicente Reig"; p.email = "vicente@propertybase.com"}
42
+ @expected_pips = [@chris, @konsti, @vicente]
43
+ end
44
+
45
+ it 'should count three people' do
46
+ @person_parser.count.should == 3
47
+ end
48
+
49
+ it 'should extract three people' do
50
+ people = @person_parser.all
51
+ people.should include @chris
52
+ people.should include @konsti
53
+ people.should include @vicente
54
+ end
55
+
56
+ it 'should extract three people in three iterations' do
57
+ @person_parser.each { |person|
58
+ @expected_pips.should include person
59
+ }
60
+ end
61
+
62
+ it 'should extract three people in three batches' do
63
+ @person_parser.in_groups_of(1) { |group|
64
+ @expected_pips.should include group.first
65
+ }
66
+ end
67
+ end
data/virgola.gemspec ADDED
@@ -0,0 +1,28 @@
1
+ # -*- encoding: utf-8 -*-
2
+ $:.push File.expand_path("../lib", __FILE__)
3
+ require "virgola/version"
4
+
5
+ Gem::Specification.new do |s|
6
+ s.platform = Gem::Platform::RUBY
7
+ s.name = 'virgola'
8
+ s.version = Virgola::VERSION
9
+ s.summary = 'An attempt to make CSV parsing and mapping suck less.'
10
+ s.description = 'Virgola is a CSV to Ruby objects mapper.'
11
+ s.files = Dir.glob("{lib,spec}/**/*") + %w[License Rakefile README.rdoc]
12
+ s.required_ruby_version = '>= 1.9.2'
13
+ s.required_rubygems_version = '>= 1.8.11'
14
+
15
+ s.author = 'Vicente Reig Rincón de Arellano'
16
+ s.email = 'vicente.reig@gmail.com'
17
+ s.homepage = 'http://github.com/vicentereig/virgola'
18
+
19
+ s.add_dependency('activesupport', '3.1.3')
20
+ s.add_dependency('activemodel', '3.1.3')
21
+ s.add_dependency('bundler', '~> 1.0')
22
+
23
+ s.files = `git ls-files`.split("\n")
24
+ s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
25
+ # s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
26
+ s.require_paths = ["lib"]
27
+
28
+ end
metadata ADDED
@@ -0,0 +1,99 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: virgola
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Vicente Reig Rincón de Arellano
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2012-02-14 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: activesupport
16
+ requirement: &70151194729640 !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - =
20
+ - !ruby/object:Gem::Version
21
+ version: 3.1.3
22
+ type: :runtime
23
+ prerelease: false
24
+ version_requirements: *70151194729640
25
+ - !ruby/object:Gem::Dependency
26
+ name: activemodel
27
+ requirement: &70151194728980 !ruby/object:Gem::Requirement
28
+ none: false
29
+ requirements:
30
+ - - =
31
+ - !ruby/object:Gem::Version
32
+ version: 3.1.3
33
+ type: :runtime
34
+ prerelease: false
35
+ version_requirements: *70151194728980
36
+ - !ruby/object:Gem::Dependency
37
+ name: bundler
38
+ requirement: &70151194728200 !ruby/object:Gem::Requirement
39
+ none: false
40
+ requirements:
41
+ - - ~>
42
+ - !ruby/object:Gem::Version
43
+ version: '1.0'
44
+ type: :runtime
45
+ prerelease: false
46
+ version_requirements: *70151194728200
47
+ description: Virgola is a CSV to Ruby objects mapper.
48
+ email: vicente.reig@gmail.com
49
+ executables: []
50
+ extensions: []
51
+ extra_rdoc_files: []
52
+ files:
53
+ - .gitignore
54
+ - .rvmrc
55
+ - Gemfile
56
+ - Gemfile.lock
57
+ - License
58
+ - README.rdoc
59
+ - Rakefile
60
+ - lib/virgola.rb
61
+ - lib/virgola/attribute_methods.rb
62
+ - lib/virgola/callbacks.rb
63
+ - lib/virgola/csv_parser.rb
64
+ - lib/virgola/extraction_methods.rb
65
+ - lib/virgola/version.rb
66
+ - spec/spec_helper.rb
67
+ - spec/virgola_attribute_methods_spec.rb
68
+ - spec/virgola_callbacks_spec.rb
69
+ - spec/virgola_spec.rb
70
+ - virgola.gemspec
71
+ homepage: http://github.com/vicentereig/virgola
72
+ licenses: []
73
+ post_install_message:
74
+ rdoc_options: []
75
+ require_paths:
76
+ - lib
77
+ required_ruby_version: !ruby/object:Gem::Requirement
78
+ none: false
79
+ requirements:
80
+ - - ! '>='
81
+ - !ruby/object:Gem::Version
82
+ version: 1.9.2
83
+ required_rubygems_version: !ruby/object:Gem::Requirement
84
+ none: false
85
+ requirements:
86
+ - - ! '>='
87
+ - !ruby/object:Gem::Version
88
+ version: 1.8.11
89
+ requirements: []
90
+ rubyforge_project:
91
+ rubygems_version: 1.8.16
92
+ signing_key:
93
+ specification_version: 3
94
+ summary: An attempt to make CSV parsing and mapping suck less.
95
+ test_files:
96
+ - spec/spec_helper.rb
97
+ - spec/virgola_attribute_methods_spec.rb
98
+ - spec/virgola_callbacks_spec.rb
99
+ - spec/virgola_spec.rb