potpourri 0.1.0 → 0.2.0
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.
- checksums.yaml +5 -13
- data/README.md +116 -5
- data/Rakefile +6 -0
- data/lib/extensions/active_record/active_record_extension.rb +62 -0
- data/lib/extensions/active_record/indentifier_field.rb +13 -0
- data/lib/lib/report_configs.rb +25 -0
- data/lib/lib/titleize.rb +7 -0
- data/lib/models/exportable_field.rb +7 -0
- data/lib/models/field.rb +35 -0
- data/lib/models/importable_field.rb +7 -0
- data/lib/models/report.rb +55 -0
- data/lib/potpourri.rb +5 -1
- data/lib/potpourri/version.rb +1 -1
- data/potpourri.gemspec +7 -1
- metadata +105 -14
checksums.yaml
CHANGED
@@ -1,15 +1,7 @@
|
|
1
1
|
---
|
2
|
-
|
3
|
-
metadata.gz:
|
4
|
-
|
5
|
-
data.tar.gz: !binary |-
|
6
|
-
ODU5NjhiMTk1ZGNmODdiOWI2ZGU3ZjNkZjc2ZGRhYjNkZWM2Y2YzOQ==
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 967a37b13ab8e26fda50157cb6fc92d1665e7dcd
|
4
|
+
data.tar.gz: 0bf7c3a2c6a2a1603a171b86044ec4da19b8fd06
|
7
5
|
SHA512:
|
8
|
-
metadata.gz:
|
9
|
-
|
10
|
-
NGU2MWJhNDhhOGJlZTlhZmZiMzdkNTg0YWMzYzNlMWVhY2JhZGRmNGFkNGM5
|
11
|
-
MjZmYzY0ZjA3Zjk0ZDhlYmYwMzc1OGZiZTliYTg1MzUxNTFhNjU=
|
12
|
-
data.tar.gz: !binary |-
|
13
|
-
MmRmNjhmMmE5NWI2NmVmYThhY2YwMWQ5OWE4ZmE3NDJhNjBmMzc2Mzk4Mzk3
|
14
|
-
NGRiYzU3Nzg2OWQ5YTk3MDYxN2RkMzhmZWE1OGIyNDMxODdkZDgxODllNGVi
|
15
|
-
ZTE2Mzk0NTljZWY4YTI0NzFkZTNjODdjNDcwOTc0MGU3ZjM1MjE=
|
6
|
+
metadata.gz: 7f1449404d6a6f59bc162151835488c06a8900fcc81d8753b46cb70719a38ba374243376e4649516684b62a253c3e24fec92abab5237d10a83a2380fe3415d44
|
7
|
+
data.tar.gz: 167ea8d0944bf69d4d5b4a4775639e284ebee459195df3854b6c65bde3edd2b58d2359693ac8b05f97b9398d77b34e9acee7bdf5b9e4be537dfe79ab39f10527
|
data/README.md
CHANGED
@@ -1,8 +1,5 @@
|
|
1
1
|
# Potpourri
|
2
|
-
|
3
|
-
Welcome to your new gem! In this directory, you'll find the files you need to be able to package up your Ruby library into a gem. Put your Ruby code in the file `lib/potpourri`. To experiment with that code, run `bin/console` for an interactive prompt.
|
4
|
-
|
5
|
-
TODO: Delete this and the text above, and describe your gem
|
2
|
+
A simple DSL to structure CSV importer and exporter for all of your models.
|
6
3
|
|
7
4
|
## Installation
|
8
5
|
|
@@ -22,7 +19,121 @@ Or install it yourself as:
|
|
22
19
|
|
23
20
|
## Usage
|
24
21
|
|
25
|
-
|
22
|
+
The basic implementation will work for models which accept a hash as the only argument. Start by defining a report class which inherits from `Potpourri::Report`.
|
23
|
+
|
24
|
+
```ruby
|
25
|
+
class Starship
|
26
|
+
attr_accessor :captain, :registration_number, :shield_frequency
|
27
|
+
|
28
|
+
def initialize(captain: nil, registration_number: nil, shield_frequency: nil)
|
29
|
+
captain, registation_number, shield_frequency = [captain, registation_number, shield_frequency]
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
class StarshipReport < Potpourri::Report
|
34
|
+
resource_class Starship
|
35
|
+
|
36
|
+
fields [
|
37
|
+
Potpourri::Field(:captain),
|
38
|
+
Potpourri::ExportableField(:registration_number),
|
39
|
+
Potpourri::ImportableField(:shield_frequency)
|
40
|
+
]
|
41
|
+
end
|
42
|
+
```
|
43
|
+
|
44
|
+
Thats it! Youll now be able to initialize a new Starship report which takes a path as its only argument:
|
45
|
+
|
46
|
+
```ruby
|
47
|
+
report = StarshipReport.new('starfleet/records/starships.csv')
|
48
|
+
|
49
|
+
report.export(starships)
|
50
|
+
# => a CSV object
|
51
|
+
# Captain,Registration Number
|
52
|
+
# Wharf, NX-74205
|
53
|
+
|
54
|
+
# Given a csv at the specified path
|
55
|
+
# Captain, Shield Frequency
|
56
|
+
# Sisko, 3.14159
|
57
|
+
|
58
|
+
report.import # => An array of Starship objects
|
59
|
+
```
|
60
|
+
|
61
|
+
### Customizing Fields
|
62
|
+
|
63
|
+
Fields can be customized in a number of ways. It is easy to decide what fields will be imported and which are
|
64
|
+
exported. Extra fields in an import will simply be ignored, so all generated exports are able to be imported.
|
65
|
+
|
66
|
+
- Potpourri::Field => These fields will be both imported and exported
|
67
|
+
- Potpourri::ExportableField => These fields will only be exported
|
68
|
+
- Potpourri::ImportableField => These fields will only be imported
|
69
|
+
|
70
|
+
Fields will interpolate which methods are used to get and set values on a model. They will also use a
|
71
|
+
variation of the Rails `#titleize` method to generate a header for the csv.
|
72
|
+
|
73
|
+
`Potpourri::Field.new(:captain)` use `captain` as a getter and `captain=` as a setter.
|
74
|
+
|
75
|
+
These assumptions can be easily overriden by passing some options into the Field when the report is defined.
|
76
|
+
|
77
|
+
```ruby
|
78
|
+
fields [
|
79
|
+
Potpourri::Field(:registration_number),
|
80
|
+
Potpourri::Field(:captain),
|
81
|
+
Potpourri::ImportableField(:shield_frequency)
|
82
|
+
]
|
83
|
+
...
|
84
|
+
|
85
|
+
fields [
|
86
|
+
Potpourri::Field(
|
87
|
+
:captain,
|
88
|
+
export_method: :command_officer,
|
89
|
+
import_method: :fearless_leader=,
|
90
|
+
header: 'Designation'
|
91
|
+
)
|
92
|
+
]
|
93
|
+
|
94
|
+
...
|
95
|
+
|
96
|
+
```
|
97
|
+
The importable and exportable fields also respond to the same methods, however of course they will only be either importable or exportable.
|
98
|
+
|
99
|
+
### ActiveRecord Extension
|
100
|
+
|
101
|
+
Importing and exporting dynamic models is only so useful. Enter the ActiveRecord extension. It provides a
|
102
|
+
`Potpourri::ActiveRecord::Report` class. This class is a subclass of `Potpourri::Report` so it responds in
|
103
|
+
much the same way, with some bells and whistles.
|
104
|
+
|
105
|
+
```ruby
|
106
|
+
class StarshipReport < Potpourri::ActiveRecord::Report
|
107
|
+
resource_class Starship
|
108
|
+
|
109
|
+
fields [
|
110
|
+
Potpourri::IdentifierField(:registration_number),
|
111
|
+
Potpourri::Field(:captain),
|
112
|
+
Potpourri::ImportableField(:shield_frequency)
|
113
|
+
]
|
114
|
+
|
115
|
+
can_create_new_records
|
116
|
+
can_update_existing_records
|
117
|
+
end
|
118
|
+
```
|
119
|
+
|
120
|
+
The big additions are:
|
121
|
+
- The identifierField
|
122
|
+
- This field is required to import any record
|
123
|
+
- it can be any model field so long as it is unique
|
124
|
+
- it accepts all the same options as `Potpourri::Field`
|
125
|
+
- Is not importable
|
126
|
+
|
127
|
+
- `can_create_new_records`
|
128
|
+
- lets the report create records if no match for the identifier can be found
|
129
|
+
- false by default
|
130
|
+
- accepts an argument and can be dynamically changed
|
131
|
+
|
132
|
+
- `can_update_existing_fields`
|
133
|
+
- lets the report update existing records
|
134
|
+
- will not overwrite the identifier field
|
135
|
+
- false by default
|
136
|
+
- accepts an argument and can be dynamically changed
|
26
137
|
|
27
138
|
## Development
|
28
139
|
|
data/Rakefile
CHANGED
@@ -0,0 +1,62 @@
|
|
1
|
+
module Potpourri
|
2
|
+
module ActiveRecordExtension
|
3
|
+
def self.included(mod)
|
4
|
+
raise NotAReport unless mod.ancestors.include?(Report)
|
5
|
+
mod.extend ClassMethods
|
6
|
+
end
|
7
|
+
|
8
|
+
class MissingIdentifierField < StandardError; end
|
9
|
+
class RecordNotFound < StandardError; end
|
10
|
+
|
11
|
+
def can_update_existing_records?
|
12
|
+
self.class.instance_variable_get '@can_update_existing_records'
|
13
|
+
end
|
14
|
+
|
15
|
+
def can_create_new_records?
|
16
|
+
self.class.instance_variable_get '@can_create_new_records'
|
17
|
+
end
|
18
|
+
|
19
|
+
|
20
|
+
def identifier_field
|
21
|
+
fields.detect &:identifier?
|
22
|
+
end
|
23
|
+
|
24
|
+
def import
|
25
|
+
resources = super
|
26
|
+
resources.each { |resource| resource.save! }
|
27
|
+
end
|
28
|
+
|
29
|
+
private
|
30
|
+
|
31
|
+
def fetch_resource(row)
|
32
|
+
raise MissingIdentifierField unless importable?
|
33
|
+
|
34
|
+
return find_record(row) unless can_create_new_records?
|
35
|
+
return resource_class.new unless can_update_existing_records?
|
36
|
+
|
37
|
+
resource = resource_class.find_by(id_params row) || resource_class.new
|
38
|
+
end
|
39
|
+
|
40
|
+
def find_record(row)
|
41
|
+
resource = resource_class.find_by! id_params(row)
|
42
|
+
end
|
43
|
+
|
44
|
+
def importable?
|
45
|
+
(can_create_new_records? || can_update_existing_records?) && identifier_field
|
46
|
+
end
|
47
|
+
|
48
|
+
def id_params(row)
|
49
|
+
Hash[identifier_field.export_method, row[identifier_field.header]]
|
50
|
+
end
|
51
|
+
|
52
|
+
module ClassMethods
|
53
|
+
def create_new_records(flag = true)
|
54
|
+
@can_create_new_records = flag
|
55
|
+
end
|
56
|
+
|
57
|
+
def update_existing_records(flag = true)
|
58
|
+
@can_update_existing_records = flag
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
module Potpourri
|
2
|
+
module ReportConfigs
|
3
|
+
def self.included(mod)
|
4
|
+
mod.extend ClassMethods
|
5
|
+
end
|
6
|
+
|
7
|
+
def fields
|
8
|
+
self.class.instance_variable_get '@fields'
|
9
|
+
end
|
10
|
+
|
11
|
+
def resource_class
|
12
|
+
self.class.instance_variable_get '@klass'
|
13
|
+
end
|
14
|
+
|
15
|
+
module ClassMethods
|
16
|
+
def fields(fields)
|
17
|
+
@fields = fields
|
18
|
+
end
|
19
|
+
|
20
|
+
def resource_class(klass)
|
21
|
+
@klass = klass
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
data/lib/lib/titleize.rb
ADDED
data/lib/models/field.rb
ADDED
@@ -0,0 +1,35 @@
|
|
1
|
+
module Potpourri
|
2
|
+
class Field
|
3
|
+
include Potpourri::Titleize
|
4
|
+
|
5
|
+
class Unimportable < StandardError; end
|
6
|
+
class Unexportable < StandardError; end
|
7
|
+
|
8
|
+
attr_reader :name, :header, :export_method, :import_method
|
9
|
+
|
10
|
+
def initialize(name, options = {})
|
11
|
+
@export_method = options[:export_method] || name.to_sym
|
12
|
+
@import_method = options[:import_method] || "#{ name }=".to_sym
|
13
|
+
@header = options[:header] || titleize(name)
|
14
|
+
@name = name.to_sym
|
15
|
+
end
|
16
|
+
|
17
|
+
def importable?
|
18
|
+
true
|
19
|
+
end
|
20
|
+
|
21
|
+
def exportable?
|
22
|
+
true
|
23
|
+
end
|
24
|
+
|
25
|
+
def import(resource, value)
|
26
|
+
raise Unimportable unless importable?
|
27
|
+
resource.public_send import_method, value
|
28
|
+
end
|
29
|
+
|
30
|
+
def export(resource)
|
31
|
+
raise Unexportable unless exportable?
|
32
|
+
resource.public_send export_method
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
@@ -0,0 +1,55 @@
|
|
1
|
+
require 'csv'
|
2
|
+
|
3
|
+
module Potpourri
|
4
|
+
class Report
|
5
|
+
include ReportConfigs
|
6
|
+
|
7
|
+
attr_reader :path
|
8
|
+
|
9
|
+
def initialize(path)
|
10
|
+
@path = path
|
11
|
+
end
|
12
|
+
|
13
|
+
def headers
|
14
|
+
fields.map &:header
|
15
|
+
end
|
16
|
+
|
17
|
+
def import
|
18
|
+
CSV.read(path, headers: true, converters: :numeric).map do |row|
|
19
|
+
resource = fetch_resource(row)
|
20
|
+
|
21
|
+
importable_fields.each do |field|
|
22
|
+
field.import resource, row[field.header]
|
23
|
+
end
|
24
|
+
|
25
|
+
resource
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
def export(collection)
|
30
|
+
CSV.open(path, 'w') do |csv|
|
31
|
+
csv << headers
|
32
|
+
|
33
|
+
collection.each do |item|
|
34
|
+
csv << exportable_fields.map { |field| field.export item }
|
35
|
+
end
|
36
|
+
|
37
|
+
csv
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
private
|
42
|
+
|
43
|
+
def importable_fields
|
44
|
+
fields.select &:importable?
|
45
|
+
end
|
46
|
+
|
47
|
+
def exportable_fields
|
48
|
+
fields.select &:exportable?
|
49
|
+
end
|
50
|
+
|
51
|
+
def fetch_resource(row)
|
52
|
+
resource_class.new
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
data/lib/potpourri.rb
CHANGED
@@ -1,5 +1,9 @@
|
|
1
1
|
require "potpourri/version"
|
2
2
|
|
3
|
+
ROOT = File.expand_path '../', __FILE__
|
4
|
+
|
3
5
|
module Potpourri
|
4
|
-
|
6
|
+
Dir.glob(File.join ROOT, 'lib/**/*.rb').each { |f| require f }
|
7
|
+
Dir.glob(File.join ROOT, 'models/**/*.rb').each { |f| require f }
|
8
|
+
Dir.glob(File.join ROOT, 'extensions/**/*.rb').each { |f| require f }
|
5
9
|
end
|
data/lib/potpourri/version.rb
CHANGED
data/potpourri.gemspec
CHANGED
@@ -10,7 +10,7 @@ Gem::Specification.new do |spec|
|
|
10
10
|
spec.email = ["brendan.g.deere@gmail.com"]
|
11
11
|
|
12
12
|
spec.summary = %q{Because you're tired of writting csv importer and exporters.}
|
13
|
-
spec.description = %q{A simple DSL to structure CSV importer and
|
13
|
+
spec.description = %q{A simple DSL to structure CSV importer and exporter for all of your models.}
|
14
14
|
spec.homepage = "https://github.com/brendandeere/potpourri"
|
15
15
|
|
16
16
|
spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
|
@@ -21,6 +21,12 @@ Gem::Specification.new do |spec|
|
|
21
21
|
if spec.respond_to?(:metadata)
|
22
22
|
end
|
23
23
|
|
24
|
+
spec.add_development_dependency "activerecord"
|
25
|
+
spec.add_development_dependency "sqlite3"
|
24
26
|
spec.add_development_dependency "bundler", "~> 1.9"
|
25
27
|
spec.add_development_dependency "rake", "~> 10.0"
|
28
|
+
spec.add_development_dependency "pry"
|
29
|
+
spec.add_development_dependency "rspec"
|
30
|
+
spec.add_development_dependency "simplecov"
|
31
|
+
spec.add_development_dependency "database_cleaner"
|
26
32
|
end
|
metadata
CHANGED
@@ -1,59 +1,150 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: potpourri
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.2.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- brendandeere
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2015-11-
|
11
|
+
date: 2015-11-25 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: activerecord
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - ">="
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '0'
|
20
|
+
type: :development
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - ">="
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '0'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: sqlite3
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - ">="
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '0'
|
34
|
+
type: :development
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - ">="
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '0'
|
13
41
|
- !ruby/object:Gem::Dependency
|
14
42
|
name: bundler
|
15
43
|
requirement: !ruby/object:Gem::Requirement
|
16
44
|
requirements:
|
17
|
-
- - ~>
|
45
|
+
- - "~>"
|
18
46
|
- !ruby/object:Gem::Version
|
19
47
|
version: '1.9'
|
20
48
|
type: :development
|
21
49
|
prerelease: false
|
22
50
|
version_requirements: !ruby/object:Gem::Requirement
|
23
51
|
requirements:
|
24
|
-
- - ~>
|
52
|
+
- - "~>"
|
25
53
|
- !ruby/object:Gem::Version
|
26
54
|
version: '1.9'
|
27
55
|
- !ruby/object:Gem::Dependency
|
28
56
|
name: rake
|
29
57
|
requirement: !ruby/object:Gem::Requirement
|
30
58
|
requirements:
|
31
|
-
- - ~>
|
59
|
+
- - "~>"
|
32
60
|
- !ruby/object:Gem::Version
|
33
61
|
version: '10.0'
|
34
62
|
type: :development
|
35
63
|
prerelease: false
|
36
64
|
version_requirements: !ruby/object:Gem::Requirement
|
37
65
|
requirements:
|
38
|
-
- - ~>
|
66
|
+
- - "~>"
|
39
67
|
- !ruby/object:Gem::Version
|
40
68
|
version: '10.0'
|
41
|
-
|
42
|
-
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: pry
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - ">="
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: '0'
|
76
|
+
type: :development
|
77
|
+
prerelease: false
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - ">="
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: '0'
|
83
|
+
- !ruby/object:Gem::Dependency
|
84
|
+
name: rspec
|
85
|
+
requirement: !ruby/object:Gem::Requirement
|
86
|
+
requirements:
|
87
|
+
- - ">="
|
88
|
+
- !ruby/object:Gem::Version
|
89
|
+
version: '0'
|
90
|
+
type: :development
|
91
|
+
prerelease: false
|
92
|
+
version_requirements: !ruby/object:Gem::Requirement
|
93
|
+
requirements:
|
94
|
+
- - ">="
|
95
|
+
- !ruby/object:Gem::Version
|
96
|
+
version: '0'
|
97
|
+
- !ruby/object:Gem::Dependency
|
98
|
+
name: simplecov
|
99
|
+
requirement: !ruby/object:Gem::Requirement
|
100
|
+
requirements:
|
101
|
+
- - ">="
|
102
|
+
- !ruby/object:Gem::Version
|
103
|
+
version: '0'
|
104
|
+
type: :development
|
105
|
+
prerelease: false
|
106
|
+
version_requirements: !ruby/object:Gem::Requirement
|
107
|
+
requirements:
|
108
|
+
- - ">="
|
109
|
+
- !ruby/object:Gem::Version
|
110
|
+
version: '0'
|
111
|
+
- !ruby/object:Gem::Dependency
|
112
|
+
name: database_cleaner
|
113
|
+
requirement: !ruby/object:Gem::Requirement
|
114
|
+
requirements:
|
115
|
+
- - ">="
|
116
|
+
- !ruby/object:Gem::Version
|
117
|
+
version: '0'
|
118
|
+
type: :development
|
119
|
+
prerelease: false
|
120
|
+
version_requirements: !ruby/object:Gem::Requirement
|
121
|
+
requirements:
|
122
|
+
- - ">="
|
123
|
+
- !ruby/object:Gem::Version
|
124
|
+
version: '0'
|
125
|
+
description: A simple DSL to structure CSV importer and exporter for all of your models.
|
43
126
|
email:
|
44
127
|
- brendan.g.deere@gmail.com
|
45
128
|
executables: []
|
46
129
|
extensions: []
|
47
130
|
extra_rdoc_files: []
|
48
131
|
files:
|
49
|
-
- .gitignore
|
50
|
-
- .rspec
|
51
|
-
- .travis.yml
|
132
|
+
- ".gitignore"
|
133
|
+
- ".rspec"
|
134
|
+
- ".travis.yml"
|
52
135
|
- Gemfile
|
53
136
|
- README.md
|
54
137
|
- Rakefile
|
55
138
|
- bin/console
|
56
139
|
- bin/setup
|
140
|
+
- lib/extensions/active_record/active_record_extension.rb
|
141
|
+
- lib/extensions/active_record/indentifier_field.rb
|
142
|
+
- lib/lib/report_configs.rb
|
143
|
+
- lib/lib/titleize.rb
|
144
|
+
- lib/models/exportable_field.rb
|
145
|
+
- lib/models/field.rb
|
146
|
+
- lib/models/importable_field.rb
|
147
|
+
- lib/models/report.rb
|
57
148
|
- lib/potpourri.rb
|
58
149
|
- lib/potpourri/version.rb
|
59
150
|
- potpourri.gemspec
|
@@ -66,17 +157,17 @@ require_paths:
|
|
66
157
|
- lib
|
67
158
|
required_ruby_version: !ruby/object:Gem::Requirement
|
68
159
|
requirements:
|
69
|
-
- -
|
160
|
+
- - ">="
|
70
161
|
- !ruby/object:Gem::Version
|
71
162
|
version: '0'
|
72
163
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
73
164
|
requirements:
|
74
|
-
- -
|
165
|
+
- - ">="
|
75
166
|
- !ruby/object:Gem::Version
|
76
167
|
version: '0'
|
77
168
|
requirements: []
|
78
169
|
rubyforge_project:
|
79
|
-
rubygems_version: 2.
|
170
|
+
rubygems_version: 2.2.3
|
80
171
|
signing_key:
|
81
172
|
specification_version: 4
|
82
173
|
summary: Because you're tired of writting csv importer and exporters.
|