virgola 0.0.1

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