csv_madness 0.0.3 → 0.0.4
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGELOG.markdown +17 -0
- data/Gemfile +3 -0
- data/README.rdoc +5 -3
- data/Rakefile +3 -1
- data/VERSION +1 -1
- data/lib/csv_madness/record.rb +13 -3
- data/lib/csv_madness/sheet.rb +83 -15
- data/lib/csv_madness.rb +4 -1
- data/test/helper.rb +82 -0
- data/test/test_csv_madness.rb +52 -22
- data/test/test_sheet.rb +24 -0
- metadata +21 -3
data/CHANGELOG.markdown
ADDED
@@ -0,0 +1,17 @@
|
|
1
|
+
0.0.4
|
2
|
+
=====
|
3
|
+
|
4
|
+
* Fixed serious bug for default column names. record.middle_name instead of record.middlename
|
5
|
+
* Spreadsheet can be re-read from file by calling @sheet.reload_spreadsheet(opts)
|
6
|
+
|
7
|
+
|
8
|
+
0.0.3
|
9
|
+
=====
|
10
|
+
|
11
|
+
* Feature: can add and drop columns from spreadsheets
|
12
|
+
|
13
|
+
|
14
|
+
0.0.2
|
15
|
+
=====
|
16
|
+
|
17
|
+
* Aw, hell. I don't remember.
|
data/Gemfile
CHANGED
data/README.rdoc
CHANGED
@@ -121,9 +121,9 @@ sheet.write_to_file( "~/data/people.clean.csv", force_quotes: true ) # save the
|
|
121
121
|
You could do something similar to clean and standardize phone numbers, detect and delete/complete invalid emails, etc.
|
122
122
|
|
123
123
|
|
124
|
-
=== Adding and
|
124
|
+
=== Adding, removing, and renaming columns ===
|
125
125
|
|
126
|
-
# Add 72 years to the date born.
|
126
|
+
# Add 72 years to the date born.
|
127
127
|
sheet.set_column_type( :born, :date ) # replace date strings with Time objects
|
128
128
|
|
129
129
|
sheet.add_column( :expected_death_date ) do |date, record|
|
@@ -135,8 +135,10 @@ puts sheet[0].expected_death_date # should be in 2058
|
|
135
135
|
# But that's just morbid, so we drop the column
|
136
136
|
sheet.drop_column( :expected_death_date )
|
137
137
|
|
138
|
+
# Or, if you think you need the information, but need to be a bit more euphemistic about it
|
139
|
+
sheet.rename_column( :expected_death_date, :expiration_date )
|
138
140
|
|
139
|
-
=== Using columns
|
141
|
+
=== Using columns ===
|
140
142
|
|
141
143
|
sheet.set_column_type( :id, :integer )
|
142
144
|
|
data/Rakefile
CHANGED
@@ -33,9 +33,11 @@ Jeweler::Tasks.new do |gem|
|
|
33
33
|
"./VERSION",
|
34
34
|
"./README.rdoc",
|
35
35
|
"./Rakefile",
|
36
|
+
"./CHANGELOG.markdown",
|
36
37
|
"./test/csv/simple.csv",
|
37
38
|
"./test/helper.rb",
|
38
|
-
"./test/test_csv_madness.rb"
|
39
|
+
"./test/test_csv_madness.rb",
|
40
|
+
"./test/test_sheet.rb" ]
|
39
41
|
end
|
40
42
|
|
41
43
|
Jeweler::RubygemsDotOrgTasks.new
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.0.
|
1
|
+
0.0.4
|
data/lib/csv_madness/record.rb
CHANGED
@@ -13,11 +13,21 @@ module CsvMadness
|
|
13
13
|
end
|
14
14
|
|
15
15
|
def [] key
|
16
|
-
|
16
|
+
case key
|
17
|
+
when String, Integer
|
18
|
+
@csv_data[key]
|
19
|
+
when Symbol
|
20
|
+
@csv_data[key.to_s]
|
21
|
+
end
|
17
22
|
end
|
18
23
|
|
19
24
|
def []= key, val
|
20
|
-
|
25
|
+
case key
|
26
|
+
when String, Integer
|
27
|
+
@csv_data[key] = val
|
28
|
+
when Symbol
|
29
|
+
@csv_data[key.to_s] = val
|
30
|
+
end
|
21
31
|
end
|
22
32
|
|
23
33
|
def columns
|
@@ -37,7 +47,7 @@ module CsvMadness
|
|
37
47
|
end
|
38
48
|
|
39
49
|
def blank?( col )
|
40
|
-
(self.send( col ).to_s || "").strip.length == 0
|
50
|
+
(self.send( col.to_sym ).to_s || "").strip.length == 0
|
41
51
|
end
|
42
52
|
end
|
43
53
|
end
|
data/lib/csv_madness/sheet.rb
CHANGED
@@ -30,7 +30,8 @@ module CsvMadness
|
|
30
30
|
# Used to make getter/setter names out of the original header strings.
|
31
31
|
# " hello;: world! " => :hello_world
|
32
32
|
def self.getter_name( name )
|
33
|
-
name = name.strip.gsub(/\s+/,"_").gsub(/(\W|_)+/, "" ).downcase
|
33
|
+
name = name.strip.gsub( /\s+/, "_" ).gsub( /(\W|_)+/, "_" ).downcase
|
34
|
+
name = name.gsub( /_+$/, "" )
|
34
35
|
if name.match( /^\d/ )
|
35
36
|
name = "_#{name}"
|
36
37
|
end
|
@@ -43,9 +44,17 @@ module CsvMadness
|
|
43
44
|
def self.add_search_path( path )
|
44
45
|
@search_paths ||= []
|
45
46
|
path = Pathname.new( path ).expand_path
|
47
|
+
unless path.directory?
|
48
|
+
raise "The given path does not exist"
|
49
|
+
end
|
50
|
+
|
46
51
|
@search_paths << path unless @search_paths.include?( path )
|
47
52
|
end
|
48
53
|
|
54
|
+
def self.search_paths
|
55
|
+
@search_paths
|
56
|
+
end
|
57
|
+
|
49
58
|
def self.from( csv_file, opts = {} )
|
50
59
|
if f = find_spreadsheet_in_filesystem( csv_file )
|
51
60
|
Sheet.new( f, opts )
|
@@ -83,7 +92,7 @@ module CsvMadness
|
|
83
92
|
end
|
84
93
|
|
85
94
|
def self.write_to_file( spreadsheet, file, opts = {} )
|
86
|
-
file =
|
95
|
+
file = file.fwf_filepath.expand_path
|
87
96
|
File.open( file, "w" ) do |f|
|
88
97
|
f << spreadsheet.to_csv( opts )
|
89
98
|
end
|
@@ -99,7 +108,7 @@ module CsvMadness
|
|
99
108
|
end
|
100
109
|
end
|
101
110
|
|
102
|
-
attr_reader :columns, :records, :spreadsheet_file, :record_class
|
111
|
+
attr_reader :columns, :index_columns, :records, :spreadsheet_file, :record_class
|
103
112
|
# opts:
|
104
113
|
# index: ( [:id, :id2 ] )
|
105
114
|
# columns you want mapped for quick
|
@@ -115,28 +124,37 @@ module CsvMadness
|
|
115
124
|
# header: false
|
116
125
|
# anything else, we assume the csv file has a header row
|
117
126
|
def initialize( spreadsheet, opts = {} )
|
118
|
-
|
127
|
+
if spreadsheet.is_a?(Array)
|
128
|
+
@spreadsheet_file = nil
|
129
|
+
|
130
|
+
else
|
131
|
+
@spreadsheet_file = self.class.find_spreadsheet_in_filesystem( spreadsheet )
|
132
|
+
end
|
119
133
|
@opts = opts
|
120
134
|
@opts[:header] = (@opts[:header] == false ? false : true) # true unless already explicitly set to false
|
121
135
|
|
136
|
+
reload_spreadsheet
|
137
|
+
end
|
138
|
+
|
139
|
+
def reload_spreadsheet( opts = @opts )
|
122
140
|
load_csv
|
123
|
-
|
124
|
-
set_initial_columns( @opts[:columns] )
|
125
|
-
|
126
|
-
|
141
|
+
set_initial_columns( opts[:columns] )
|
127
142
|
create_record_class
|
128
143
|
package
|
129
144
|
|
130
|
-
|
145
|
+
set_index_columns( opts[:index] )
|
146
|
+
reindex
|
147
|
+
end
|
148
|
+
|
149
|
+
def set_index_columns( index_columns )
|
150
|
+
@index_columns = case index_columns
|
131
151
|
when NilClass
|
132
152
|
[]
|
133
153
|
when Symbol
|
134
|
-
[
|
154
|
+
[ index_columns ]
|
135
155
|
when Array
|
136
|
-
|
156
|
+
index_columns
|
137
157
|
end
|
138
|
-
|
139
|
-
reindex
|
140
158
|
end
|
141
159
|
|
142
160
|
def [] offset
|
@@ -196,8 +214,9 @@ module CsvMadness
|
|
196
214
|
end
|
197
215
|
end
|
198
216
|
|
199
|
-
# if column doesn't exist, silently fails. Proper behavior? Dunno.
|
200
217
|
def alter_column( column, blank = :undefined, &block )
|
218
|
+
raise "Column does not exist: #{column}" unless @columns.include?( column )
|
219
|
+
|
201
220
|
if cindex = @columns.index( column )
|
202
221
|
for record in @records
|
203
222
|
if record.blank?(column) && blank != :undefined
|
@@ -209,8 +228,9 @@ module CsvMadness
|
|
209
228
|
end
|
210
229
|
end
|
211
230
|
|
231
|
+
# If no block given, adds an empty column
|
212
232
|
def add_column( column, &block )
|
213
|
-
raise "Column already exists" if @columns.include?( column )
|
233
|
+
raise "Column already exists: #{column}" if @columns.include?( column )
|
214
234
|
@columns << column
|
215
235
|
|
216
236
|
# add empty column to each row
|
@@ -241,10 +261,45 @@ module CsvMadness
|
|
241
261
|
update_data_accessor_module
|
242
262
|
end
|
243
263
|
|
264
|
+
def rename_column( column, new_name )
|
265
|
+
@columns[@columns.index(column)] = new_name
|
266
|
+
rename_index_column( column, new_name ) if @index_columns.include?( column )
|
267
|
+
update_data_accessor_module
|
268
|
+
end
|
269
|
+
|
244
270
|
def set_column_type( column, type, blank = :undefined )
|
245
271
|
alter_column( column, blank, &COLUMN_TYPES[type] )
|
246
272
|
end
|
247
273
|
|
274
|
+
|
275
|
+
# If :reverse_merge is true, then the dest column is only overwritten for records where :dest is blank
|
276
|
+
def merge_columns( source, dest, opts = {} )
|
277
|
+
opts = { :drop_source => true, :reverse_merge => false, :default => "" }.merge( opts )
|
278
|
+
column_must_exist( source, dest )
|
279
|
+
|
280
|
+
self.records.each do |record|
|
281
|
+
if opts[:reverse_merge] == false || record.blank?( dest )
|
282
|
+
record[dest] = record.blank?(source) ? opts[:default] : record[source]
|
283
|
+
end
|
284
|
+
end
|
285
|
+
|
286
|
+
self.drop_column( source ) if opts[:drop_source]
|
287
|
+
end
|
288
|
+
|
289
|
+
# By default, the
|
290
|
+
def concat_columns( col1, col2, opts = {} )
|
291
|
+
opts = {:separator => '', :out => col1}.merge( opts )
|
292
|
+
|
293
|
+
column_must_exist( col1, col2 )
|
294
|
+
self.add_column( opts[:out] ) unless self.columns.include?( opts[:out] )
|
295
|
+
|
296
|
+
for record in self.records
|
297
|
+
record[ opts[:out] ] = "#{record[col1]}#{opts[:separator]}#{record[col2]}"
|
298
|
+
end
|
299
|
+
end
|
300
|
+
|
301
|
+
alias :concatenate :concat_columns
|
302
|
+
|
248
303
|
# Note: If a block is given, the mod arg will be ignored.
|
249
304
|
def add_record_methods( mod = nil, &block )
|
250
305
|
if block_given?
|
@@ -285,6 +340,13 @@ module CsvMadness
|
|
285
340
|
end
|
286
341
|
end
|
287
342
|
|
343
|
+
# shouldn't require reindex
|
344
|
+
def rename_index_column( column, new_name )
|
345
|
+
@index_columns[ @index_columns.index( column ) ] = new_name
|
346
|
+
@indexes[new_name] = @indexes[column]
|
347
|
+
@indexes.delete(column)
|
348
|
+
end
|
349
|
+
|
288
350
|
# Each spreadsheet has its own anonymous record class, and each CSV row instantiates
|
289
351
|
# a record of this class. This is where the getters and setters come from.
|
290
352
|
def create_record_class
|
@@ -374,5 +436,11 @@ module CsvMadness
|
|
374
436
|
def update_data_accessor_module
|
375
437
|
@module.remap_accessors( columns_to_mapping )
|
376
438
|
end
|
439
|
+
|
440
|
+
def column_must_exist( *cols )
|
441
|
+
for col in cols
|
442
|
+
raise ArgumentError.new( "#{caller[0]}: column :#{col} does not exist.") unless self.columns.include?(col)
|
443
|
+
end
|
444
|
+
end
|
377
445
|
end
|
378
446
|
end
|
data/lib/csv_madness.rb
CHANGED
@@ -1,5 +1,5 @@
|
|
1
1
|
require 'csv'
|
2
|
-
require '
|
2
|
+
require 'fun_with_files'
|
3
3
|
require 'time' # to use Time.parse to parse cells to get the date
|
4
4
|
require 'debugger'
|
5
5
|
|
@@ -7,6 +7,9 @@ require_relative 'csv_madness/data_accessor_module'
|
|
7
7
|
require_relative 'csv_madness/sheet'
|
8
8
|
require_relative 'csv_madness/record'
|
9
9
|
|
10
|
+
|
11
|
+
FunWith::Files::RootPath.rootify( CsvMadness, __FILE__.fwf_filepath.dirname.up )
|
12
|
+
|
10
13
|
CsvMadness.class_eval do
|
11
14
|
def self.load( csv, opts = {} )
|
12
15
|
CsvMadness::Sheet.from( csv, opts )
|
data/test/helper.rb
CHANGED
@@ -19,3 +19,85 @@ require 'csv_madness'
|
|
19
19
|
|
20
20
|
class Test::Unit::TestCase
|
21
21
|
end
|
22
|
+
|
23
|
+
class MadTestCase < Test::Unit::TestCase
|
24
|
+
MARY_ID = "1"
|
25
|
+
BILL_ID = "2"
|
26
|
+
DARWIN_ID = "3"
|
27
|
+
CHUCK_ID = "4"
|
28
|
+
|
29
|
+
def load_mary
|
30
|
+
id = @simple.index_columns.first
|
31
|
+
@mary = @simple.fetch( id, MARY_ID )
|
32
|
+
end
|
33
|
+
|
34
|
+
def load_bill
|
35
|
+
id = @simple.index_columns.first
|
36
|
+
@bill = @simple.fetch( id, BILL_ID )
|
37
|
+
end
|
38
|
+
|
39
|
+
def load_darwin
|
40
|
+
id = @simple.index_columns.first
|
41
|
+
@darwin = @simple.fetch( id, DARWIN_ID )
|
42
|
+
end
|
43
|
+
|
44
|
+
def load_chuck
|
45
|
+
id = @simple.index_columns.first
|
46
|
+
@chuck = @simple.fetch( id, CHUCK_ID )
|
47
|
+
end
|
48
|
+
|
49
|
+
def set_person_records
|
50
|
+
load_mary
|
51
|
+
load_darwin
|
52
|
+
load_bill
|
53
|
+
load_chuck
|
54
|
+
end
|
55
|
+
|
56
|
+
def muck_up_spreadsheet
|
57
|
+
@simple.add_column(:scrambled_name) do |val, record|
|
58
|
+
record.fname.chars.map(&:to_s).zip( record.lname.chars.map(&:to_s) ).flatten.compact.join
|
59
|
+
end
|
60
|
+
|
61
|
+
@simple.alter_column(:id) do |val|
|
62
|
+
(val.to_i << 8) % 27
|
63
|
+
end
|
64
|
+
|
65
|
+
@simple.set_column_type(:id, :float)
|
66
|
+
@simple.set_column_type(:born, :date)
|
67
|
+
|
68
|
+
@simple.alter_column(:born) do |val|
|
69
|
+
if val.is_a?(String)
|
70
|
+
-1.0
|
71
|
+
else
|
72
|
+
(Time.now - val).to_f
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
@simple.drop_column(:fname)
|
77
|
+
@simple.drop_column(:lname)
|
78
|
+
end
|
79
|
+
|
80
|
+
def set_spreadsheet_paths
|
81
|
+
@csv_search_path = Pathname.new( __FILE__ ).dirname.join("csv")
|
82
|
+
@csv_output_path = @csv_search_path.join("out")
|
83
|
+
CsvMadness::Sheet.add_search_path( @csv_search_path )
|
84
|
+
CsvMadness::Sheet.add_search_path( @csv_output_path )
|
85
|
+
end
|
86
|
+
|
87
|
+
def load_simple_spreadsheet
|
88
|
+
@simple = CsvMadness.load( "simple.csv", index: [:id] )
|
89
|
+
end
|
90
|
+
|
91
|
+
def unload_simple_spreadsheet
|
92
|
+
@simple = nil
|
93
|
+
end
|
94
|
+
|
95
|
+
def empty_output_folder
|
96
|
+
if defined?(FileUtils)
|
97
|
+
FileUtils.rm_rf( Dir.glob( @csv_output_path.join("**","*") ) )
|
98
|
+
else
|
99
|
+
puts "fileutils not defined"
|
100
|
+
`rm -rf #{@csv_output_path.join('*')}`
|
101
|
+
end
|
102
|
+
end
|
103
|
+
end
|
data/test/test_csv_madness.rb
CHANGED
@@ -1,26 +1,21 @@
|
|
1
1
|
require 'helper'
|
2
2
|
|
3
|
-
class TestCsvMadness <
|
3
|
+
class TestCsvMadness < MadTestCase
|
4
4
|
context "all:" do
|
5
5
|
setup do
|
6
|
-
|
7
|
-
|
8
|
-
CsvMadness::Sheet.add_search_path( @csv_search_path )
|
6
|
+
set_spreadsheet_paths
|
7
|
+
load_simple_spreadsheet
|
9
8
|
end
|
10
9
|
|
11
10
|
teardown do
|
12
|
-
|
13
|
-
FileUtils.rm_rf( Dir.glob( @csv_output_path.join("**","*") ) )
|
14
|
-
else
|
15
|
-
puts "fileutils not defined"
|
16
|
-
`rm -rf #{@csv_output_path.join('*')}`
|
17
|
-
end
|
11
|
+
empty_output_folder
|
18
12
|
end
|
19
13
|
|
20
14
|
context "testing sheet basics" do
|
21
15
|
should "not accept duplicate search paths" do
|
16
|
+
@path_count = CsvMadness::Sheet.search_paths.length
|
22
17
|
CsvMadness::Sheet.add_search_path( Pathname.new( __FILE__ ).dirname.join("csv") )
|
23
|
-
assert_equal
|
18
|
+
assert_equal @path_count, CsvMadness::Sheet.search_paths.length
|
24
19
|
end
|
25
20
|
|
26
21
|
should "load a simple spreadsheet" do
|
@@ -49,11 +44,11 @@ class TestCsvMadness < Test::Unit::TestCase
|
|
49
44
|
context "testing transformations" do
|
50
45
|
context "with a simple spreadsheet loaded" do
|
51
46
|
setup do
|
52
|
-
|
47
|
+
load_simple_spreadsheet
|
53
48
|
end
|
54
49
|
|
55
50
|
teardown do
|
56
|
-
|
51
|
+
unload_simple_spreadsheet
|
57
52
|
end
|
58
53
|
|
59
54
|
should "transform every cell" do
|
@@ -154,6 +149,49 @@ class TestCsvMadness < Test::Unit::TestCase
|
|
154
149
|
assert_equal records.length, records.compact.length
|
155
150
|
assert_equal 2, records.length
|
156
151
|
assert_equal "1", records.first.id
|
152
|
+
end
|
153
|
+
|
154
|
+
should "rename columns" do
|
155
|
+
load_mary
|
156
|
+
|
157
|
+
assert_equal "Mary", @mary.fname
|
158
|
+
assert_equal "Moore", @mary.lname
|
159
|
+
assert_equal "Mary", @mary[1]
|
160
|
+
assert_equal "Moore", @mary[2]
|
161
|
+
|
162
|
+
@simple.rename_column( :fname, :first_name )
|
163
|
+
@simple.rename_column( :lname, :last_name )
|
164
|
+
|
165
|
+
assert_equal "Mary", @mary.first_name
|
166
|
+
assert_equal "Moore", @mary.last_name
|
167
|
+
assert_equal "Mary", @mary[1]
|
168
|
+
assert_equal "Moore", @mary[2]
|
169
|
+
end
|
170
|
+
|
171
|
+
should "rename an index column" do
|
172
|
+
@simple.rename_column( :id, :identifier )
|
173
|
+
@mary = @simple.fetch( :identifier, "1" )
|
174
|
+
assert_equal "1", @mary.identifier
|
175
|
+
end
|
176
|
+
|
177
|
+
should "rename an index column and ensure that the outputted spreadsheet has the new column name" do
|
178
|
+
@simple.rename_column( :id, :identifier )
|
179
|
+
@outfile = @csv_output_path.join("output.csv")
|
180
|
+
@simple.write_to_file( @outfile, force_quotes: true )
|
181
|
+
|
182
|
+
@simple = CsvMadness.load( @outfile, index: [:identifier] )
|
183
|
+
|
184
|
+
load_mary
|
185
|
+
assert_equal "Mary", @mary.fname
|
186
|
+
end
|
187
|
+
|
188
|
+
should "filter! records" do
|
189
|
+
@simple.filter! do |record|
|
190
|
+
record.id == BILL_ID || record.id == CHUCK_ID
|
191
|
+
end
|
192
|
+
|
193
|
+
assert_equal 2, @simple.records.length
|
194
|
+
|
157
195
|
end
|
158
196
|
end
|
159
197
|
end
|
@@ -194,7 +232,7 @@ class TestCsvMadness < Test::Unit::TestCase
|
|
194
232
|
context "testing add/remove column transformations" do
|
195
233
|
context "with simple spreadsheet loaded" do
|
196
234
|
setup do
|
197
|
-
|
235
|
+
load_simple_spreadsheet
|
198
236
|
end
|
199
237
|
|
200
238
|
should "add column" do
|
@@ -221,12 +259,4 @@ class TestCsvMadness < Test::Unit::TestCase
|
|
221
259
|
end
|
222
260
|
end
|
223
261
|
end
|
224
|
-
|
225
|
-
def load_simple
|
226
|
-
@simple = CsvMadness.load( "simple.csv", index: [:id] )
|
227
|
-
end
|
228
|
-
|
229
|
-
def load_mary
|
230
|
-
@mary = @simple.fetch( :id, "1" )
|
231
|
-
end
|
232
262
|
end
|
data/test/test_sheet.rb
ADDED
@@ -0,0 +1,24 @@
|
|
1
|
+
require 'helper'
|
2
|
+
|
3
|
+
class TestCsvMadness < MadTestCase
|
4
|
+
context "testing getter_name()" do
|
5
|
+
should "return proper function names" do
|
6
|
+
assert_equal :hello_world, CsvMadness::Sheet.getter_name( " heLLo __ world " )
|
7
|
+
assert_equal :_0_hello_world, CsvMadness::Sheet.getter_name( "0 heLLo __ worlD!!! " )
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
11
|
+
context "testing default spreadsheet paths" do
|
12
|
+
should "only load existing paths" do
|
13
|
+
assert_raise(RuntimeError) do
|
14
|
+
CsvMadness::Sheet.add_search_path( CsvMadness.root.join("rocaganthor") )
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
should "check a search path for files to load" do
|
19
|
+
CsvMadness::Sheet.add_search_path( CsvMadness.root.join("test", "csv") )
|
20
|
+
sheet = CsvMadness.load( "with_nils.csv" )
|
21
|
+
assert sheet.is_a?(CsvMadness::Sheet)
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: csv_madness
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.4
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,8 +9,24 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2013-
|
12
|
+
date: 2013-11-07 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: fun_with_files
|
16
|
+
requirement: !ruby/object:Gem::Requirement
|
17
|
+
none: false
|
18
|
+
requirements:
|
19
|
+
- - ! '>='
|
20
|
+
- !ruby/object:Gem::Version
|
21
|
+
version: '0'
|
22
|
+
type: :runtime
|
23
|
+
prerelease: false
|
24
|
+
version_requirements: !ruby/object:Gem::Requirement
|
25
|
+
none: false
|
26
|
+
requirements:
|
27
|
+
- - ! '>='
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
version: '0'
|
14
30
|
- !ruby/object:Gem::Dependency
|
15
31
|
name: shoulda
|
16
32
|
requirement: !ruby/object:Gem::Requirement
|
@@ -100,6 +116,7 @@ extra_rdoc_files:
|
|
100
116
|
- LICENSE.txt
|
101
117
|
- README.rdoc
|
102
118
|
files:
|
119
|
+
- ./CHANGELOG.markdown
|
103
120
|
- ./Gemfile
|
104
121
|
- ./README.rdoc
|
105
122
|
- ./Rakefile
|
@@ -111,6 +128,7 @@ files:
|
|
111
128
|
- ./test/csv/simple.csv
|
112
129
|
- ./test/helper.rb
|
113
130
|
- ./test/test_csv_madness.rb
|
131
|
+
- ./test/test_sheet.rb
|
114
132
|
- LICENSE.txt
|
115
133
|
- README.rdoc
|
116
134
|
homepage: http://github.com/darthschmoo/csv_madness
|
@@ -128,7 +146,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
128
146
|
version: '0'
|
129
147
|
segments:
|
130
148
|
- 0
|
131
|
-
hash:
|
149
|
+
hash: 1185350757253474800
|
132
150
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
133
151
|
none: false
|
134
152
|
requirements:
|