csv_pirate 2.4.4 → 3.1.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.
- data/CHANGELOG +6 -0
- data/README.rdoc +30 -20
- data/VERSION.yml +3 -3
- data/csv_pirate.gemspec +1 -1
- data/lib/csv_pirate.rb +43 -30
- data/lib/ninth_bit/pirate_ship.rb +3 -2
- metadata +1 -1
data/CHANGELOG
CHANGED
data/README.rdoc
CHANGED
|
@@ -5,30 +5,33 @@ Easily create CSVs of any data that can be derived from your models.
|
|
|
5
5
|
CsvPirate is the easy way to create a CSV of essentially anything in Rails, in full pirate regalia.
|
|
6
6
|
It works better if you are wearing a tricorne!
|
|
7
7
|
|
|
8
|
+
My goal is to have it do EVERYTHING it possibly can for me, since almost every project I do needs CSV exports.
|
|
9
|
+
|
|
8
10
|
CsvPirate only works for commissions of swag OR grub!
|
|
9
11
|
|
|
10
12
|
Initialize method (a.k.a new()) takes a hash of params:
|
|
11
13
|
|
|
12
14
|
# CsvPirate only works for commissions of swag OR grub!
|
|
13
|
-
# :swag
|
|
14
|
-
# :grub
|
|
15
|
-
# :spyglasses
|
|
16
|
-
#
|
|
17
|
-
# :booty
|
|
18
|
-
# :chart
|
|
19
|
-
# :wagonner
|
|
20
|
-
# :aft
|
|
21
|
-
# :shrouds
|
|
22
|
-
# :chronometer
|
|
23
|
-
# :gibbet
|
|
24
|
-
# :swab
|
|
15
|
+
# :swag the ARrr collection of swag to work on (optional)
|
|
16
|
+
# :grub the ARrr class that the spyglasses will be used on (optional)
|
|
17
|
+
# :spyglasses named scopes in your model that will refine the rows in the CSV according to conditions of the spyglasses,
|
|
18
|
+
# and order them according to the order of the spyglasses (optional)
|
|
19
|
+
# :booty booty (columns/methods) on your model that you want printed in the CSV, also used to create the figurehead (CSV header)
|
|
20
|
+
# :chart array of directory names (relative to rails root if using rails) which will be the filepath where you want to hide your loot
|
|
21
|
+
# :wagonner name of document where you will give detailed descriptions of the loot
|
|
22
|
+
# :aft filename extention ('.csv')
|
|
23
|
+
# :shrouds CSV column separator, default is ','. For tsv, tab-delimited, "\t"
|
|
24
|
+
# :chronometer keeps track of when you hunt for treasure
|
|
25
|
+
# :gibbet filename spacer after the date, and before the iterative counter/timestamp. MuST contain a '.'
|
|
26
|
+
# :swab can be :counter, :timestamp, or :none
|
|
25
27
|
# :counter - default, each successive run will create a new file using a counter
|
|
26
28
|
# :timestamp - each successive run will create a new file using a HHMMSS time stamp
|
|
27
29
|
# :none - no iterative file naming convention, just use waggoner and aft
|
|
28
|
-
# :mop
|
|
30
|
+
# :mop can be :clean or :dirty (:overwrite or :append) (only has an effect if :swab is :none) since overwriting is irrelevant for a new file
|
|
29
31
|
# :clear - do not use :counter or :timestamp, and instead overwrite the file
|
|
30
32
|
# :dirty - do not use :counter, or :timestamp, or :overwrite. Just keep adding on.
|
|
31
|
-
#
|
|
33
|
+
# :bury_treasure should we store the csv data as it is collected in an array in Ruby form for later use (true), or just write the CSV (false)?
|
|
34
|
+
# check the source to see if there anything else hiding in there!
|
|
32
35
|
|
|
33
36
|
The create method has the same parameters, and actually creates the CSV.
|
|
34
37
|
|
|
@@ -71,6 +74,13 @@ Plugin using Git:
|
|
|
71
74
|
ruby script/plugin install git://github.com/pboling/csv_pirate.git
|
|
72
75
|
|
|
73
76
|
|
|
77
|
+
== Upgrading
|
|
78
|
+
|
|
79
|
+
In older versions :chart was a string which indicated where you wanted to hide the loot (write the csv file)
|
|
80
|
+
Now it must be an array of directory names. So if you want your loot in "log/csv/pirates/model_name", then chart is:
|
|
81
|
+
['log','csv','pirates','model_name']
|
|
82
|
+
CsvPirate ensures that whatever you choose as your chart exists in the filesystem, and creates the directories if need be.
|
|
83
|
+
|
|
74
84
|
== Example & Usage
|
|
75
85
|
|
|
76
86
|
Assuming a Make (as in manufacturers of automobiles) model like this:
|
|
@@ -152,7 +162,7 @@ The following two sets of code are identical:
|
|
|
152
162
|
:spyglasses => [:active,:logged_in],
|
|
153
163
|
:waggoner => 'active_users_logged_in',
|
|
154
164
|
:booty => ["id","number","login","created_at"],
|
|
155
|
-
:chart => 'log
|
|
165
|
+
:chart => ['log','csv']
|
|
156
166
|
})
|
|
157
167
|
csv_pirate.hoist_mainstay() # creates CSV file and writes out the rows
|
|
158
168
|
|
|
@@ -161,7 +171,7 @@ The following two sets of code are identical:
|
|
|
161
171
|
:spyglasses => [:active,:logged_in],
|
|
162
172
|
:waggoner => 'active_users_logged_in',
|
|
163
173
|
:booty => ["id","number","login","created_at"],
|
|
164
|
-
:chart => 'log
|
|
174
|
+
:chart => ['log','csv']
|
|
165
175
|
})# creates CSV file and writes out the rows
|
|
166
176
|
|
|
167
177
|
Another example using swag instead of grub:
|
|
@@ -171,7 +181,7 @@ Another example using swag instead of grub:
|
|
|
171
181
|
:swag => users,
|
|
172
182
|
:waggoner => 'inactive_users_not_logged_in',
|
|
173
183
|
:booty => ["id","number","login","created_at"],
|
|
174
|
-
:chart => 'log
|
|
184
|
+
:chart => ['log','csv']
|
|
175
185
|
})
|
|
176
186
|
csv_pirate.hoist_mainstay()
|
|
177
187
|
|
|
@@ -181,11 +191,11 @@ Then if you want to get your hands on the loot immediately:
|
|
|
181
191
|
|
|
182
192
|
For those who can't help but copy/paste into console and then edit:
|
|
183
193
|
|
|
184
|
-
csv_pirate = CsvPirate.new({:grub => User,:spyglasses => [:active,:logged_in],:waggoner => 'active_users_logged_in',:booty => ["id","number","login","created_at"],:chart => 'log
|
|
194
|
+
csv_pirate = CsvPirate.new({:grub => User,:spyglasses => [:active,:logged_in],:waggoner => 'active_users_logged_in',:booty => ["id","number","login","created_at"],:chart => ['log','csv']})
|
|
185
195
|
|
|
186
196
|
OR
|
|
187
197
|
|
|
188
|
-
csv_pirate = CsvPirate.new({:swag => users,:waggoner => 'inactive_users_not_logged_in',:booty => ["id","number","login","created_at"],:chart => 'log
|
|
198
|
+
csv_pirate = CsvPirate.new({:swag => users,:waggoner => 'inactive_users_not_logged_in',:booty => ["id","number","login","created_at"],:chart => ['log','csv']})
|
|
189
199
|
|
|
190
200
|
|
|
191
201
|
== Downloading the CSV
|
|
@@ -257,7 +267,7 @@ You have a VehicleModel class and the same Make class as up above:
|
|
|
257
267
|
|
|
258
268
|
Then to create the CSV:
|
|
259
269
|
|
|
260
|
-
a = VehicleModel.
|
|
270
|
+
a = VehicleModel.blindfold
|
|
261
271
|
|
|
262
272
|
Then check the output from the console:
|
|
263
273
|
|
data/VERSION.yml
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
---
|
|
2
|
-
:patch:
|
|
3
|
-
:major:
|
|
4
|
-
:minor:
|
|
2
|
+
:patch: 0
|
|
3
|
+
:major: 3
|
|
4
|
+
:minor: 1
|
data/csv_pirate.gemspec
CHANGED
data/lib/csv_pirate.rb
CHANGED
|
@@ -15,7 +15,7 @@ class CsvPirate
|
|
|
15
15
|
MOP_HEADS = [:clean, :dirty]
|
|
16
16
|
|
|
17
17
|
attr_accessor :waggoner #filename
|
|
18
|
-
attr_accessor :chart #directory, default is ('log
|
|
18
|
+
attr_accessor :chart #directory, default is (['log','csv'])
|
|
19
19
|
attr_accessor :aft #extension, default is ('.csv')
|
|
20
20
|
attr_accessor :gibbet #part of the filename after waggoner and date, before swabbie and aft
|
|
21
21
|
attr_accessor :chronometer
|
|
@@ -56,7 +56,7 @@ class CsvPirate
|
|
|
56
56
|
# :spyglasses named scopes in your model that will refine the rows in the CSV according to conditions of the spyglasses,
|
|
57
57
|
# and order them according to the order of the spyglasses (optional)
|
|
58
58
|
# :booty booty (columns/methods) on your model that you want printed in the CSV, also used to create the figurehead (CSV header)
|
|
59
|
-
# :chart
|
|
59
|
+
# :chart array of directory names (relative to rails root if using rails) which will be the filepath where you want to hide your loot
|
|
60
60
|
# :wagonner name of document where you will give detailed descriptions of the loot
|
|
61
61
|
# :aft filename extention ('.csv')
|
|
62
62
|
# :shrouds CSV column separator, default is ','. For tsv, tab-delimited, "\t"
|
|
@@ -92,13 +92,15 @@ class CsvPirate
|
|
|
92
92
|
@gibbet = args.first[:gibbet] || '.export'
|
|
93
93
|
raise ArgumentError, ":gibbet is #{args.first[:gibbet].inspect}, and does not contain a '.' character, which is required for iterative filenames" if args.first[:gibbet].nil? || !args.first[:gibbet].include?('.')
|
|
94
94
|
|
|
95
|
-
@waggoner = args.first[:waggoner] || "#{self.grub}"
|
|
95
|
+
@waggoner = args.first[:waggoner] || "#{self.grub || self.swag}"
|
|
96
96
|
raise ArgumentError, ":waggoner is #{args.first[:waggoner].inspect}, and must be a string at least one character long" if args.first[:waggoner].nil? || args.first[:waggoner].length < 1
|
|
97
97
|
|
|
98
98
|
@booty = args.first[:booty] || []
|
|
99
|
-
raise ArgumentError, ":booty is #{args.first[:booty].inspect}, and must be an array of methods to call on a class for CSV data" if args.first[:booty].nil? || args.first[:booty].empty?
|
|
99
|
+
raise ArgumentError, ":booty is #{args.first[:booty].inspect}, and must be an array of methods to call on a class for CSV data" if args.first[:booty].nil? || !args.first[:booty].is_a?(Array) || args.first[:booty].empty?
|
|
100
|
+
|
|
101
|
+
@chart = args.first[:chart] || ['log','csv']
|
|
102
|
+
raise ArgumentError, ":chart is #{args.first[:chart].inspect}, and must be an array of directory names, which will become the filepath for the csv file" if args.first[:chart].nil? || !args.first[:chart].is_a?(Array) || args.first[:booty].empty?
|
|
100
103
|
|
|
101
|
-
@chart = args.first[:chart] || 'log/'
|
|
102
104
|
@aft = args.first[:aft] || '.csv'
|
|
103
105
|
@chronometer = args.first[:chronometer] || Date.today
|
|
104
106
|
|
|
@@ -112,7 +114,7 @@ class CsvPirate
|
|
|
112
114
|
|
|
113
115
|
# Initialize doesn't write anything to a CSV,
|
|
114
116
|
# but does create the traverse_board and opens the waggoner for reading / writing
|
|
115
|
-
|
|
117
|
+
self.northwest_passage unless self.astrolabe
|
|
116
118
|
|
|
117
119
|
# This will contain the text of the csv from this particular execution
|
|
118
120
|
@maroon = ""
|
|
@@ -232,28 +234,11 @@ class CsvPirate
|
|
|
232
234
|
end
|
|
233
235
|
end
|
|
234
236
|
|
|
235
|
-
def traverse_board
|
|
236
|
-
#If we have rails environment then we use rails root, otherwise self.chart stands on its own as a relative path
|
|
237
|
-
"#{defined?(Rails) ? Rails.root + '/' : defined?(RAILS_ROOT) ? RAILS_ROOT + '/' : ''}#{self.chart}"
|
|
238
|
-
end
|
|
239
|
-
|
|
240
|
-
def sand_glass
|
|
241
|
-
"#{self.chronometer.respond_to?(:strftime) ? '.' + self.chronometer.strftime("%Y%m%d") : ''}"
|
|
242
|
-
end
|
|
243
|
-
|
|
244
237
|
#complete file path
|
|
245
238
|
def poop_deck
|
|
246
239
|
"#{self.analemma}#{self.swabbie}#{self.aft}"
|
|
247
240
|
end
|
|
248
241
|
|
|
249
|
-
def merchantman
|
|
250
|
-
"#{self.waggoner}#{self.sand_glass}#{self.gibbet}"
|
|
251
|
-
end
|
|
252
|
-
|
|
253
|
-
def analemma
|
|
254
|
-
"#{self.traverse_board}#{self.merchantman}"
|
|
255
|
-
end
|
|
256
|
-
|
|
257
242
|
# Swabs the poop_deck if the mop is clean. (!)
|
|
258
243
|
def swab_poop_deck
|
|
259
244
|
self.rhumb_lines.truncate(0) if self.swab == :none && self.mop == :clean && File.size(self.poop_deck) > 0
|
|
@@ -274,6 +259,34 @@ class CsvPirate
|
|
|
274
259
|
|
|
275
260
|
protected
|
|
276
261
|
|
|
262
|
+
def traverse_board
|
|
263
|
+
#If we have rails environment then we use rails root, otherwise self.chart stands on its own as a relative path
|
|
264
|
+
"#{self.north_pole}#{self.chart.join('/')}/"
|
|
265
|
+
end
|
|
266
|
+
|
|
267
|
+
def sand_glass
|
|
268
|
+
"#{self.chronometer.respond_to?(:strftime) ? '.' + self.chronometer.strftime("%Y%m%d") : ''}"
|
|
269
|
+
end
|
|
270
|
+
|
|
271
|
+
def merchantman
|
|
272
|
+
"#{self.waggoner}#{self.sand_glass}#{self.gibbet}"
|
|
273
|
+
end
|
|
274
|
+
|
|
275
|
+
def analemma
|
|
276
|
+
"#{self.traverse_board}#{self.merchantman}"
|
|
277
|
+
end
|
|
278
|
+
|
|
279
|
+
def north_pole
|
|
280
|
+
"#{defined?(Rails) ? "#{Rails.root}/" : defined?(RAILS_ROOT) ? "#{RAILS_ROOT}/" : ''}"
|
|
281
|
+
end
|
|
282
|
+
|
|
283
|
+
def northwest_passage
|
|
284
|
+
self.chart.length.times do |i|
|
|
285
|
+
north_star = self.north_pole + self.chart[0..i].join('/')
|
|
286
|
+
Dir.mkdir(north_star) if Dir.glob(north_star).empty?
|
|
287
|
+
end
|
|
288
|
+
end
|
|
289
|
+
|
|
277
290
|
def lantern
|
|
278
291
|
"#{self.analemma}.*"
|
|
279
292
|
end
|
|
@@ -372,7 +385,7 @@ class CsvPirate
|
|
|
372
385
|
# :spyglasses => is the column to load ("find_by_#{booty}") the ARrr object for each row on the first CSV
|
|
373
386
|
# (swag OR spyglasses can be specified, but code defers to swag if provided)
|
|
374
387
|
# :waggoner => where the capn's loot was stashed (filename)
|
|
375
|
-
# :chart => directory where capn's waggoner is located
|
|
388
|
+
# :chart => array of directory names where capn's waggoner is located
|
|
376
389
|
# :astrolabe => true (file is opened at top of file in read only mode when true)
|
|
377
390
|
# The first_mate hash is:
|
|
378
391
|
# :grub => is the class on which to make booty [method] calls, or
|
|
@@ -382,23 +395,23 @@ class CsvPirate
|
|
|
382
395
|
# :spyglasses => is the column to load ("find_by_#{booty}") the ARrr object for each row on the second CSV (if grub is a class)
|
|
383
396
|
# :booty => is the methods to call on the ARrr object for each row on the second CSV
|
|
384
397
|
# :waggoner => where to stash the first mate's loot (filename)
|
|
385
|
-
# :chart => directory where first mate's waggoner is located
|
|
398
|
+
# :chart => array of directory names where first mate's waggoner is located
|
|
386
399
|
# :astrolabe => false (false is the default for astrolabe, so we could leave it off the first_mate)
|
|
387
400
|
#
|
|
388
401
|
# Example:
|
|
389
|
-
# capn = {:grub => User,:spyglasses => [:inactive],:booty => ['id','login','status'],:waggoner => 'orig',:chart => 'log
|
|
402
|
+
# capn = {:grub => User,:spyglasses => [:inactive],:booty => ['id','login','status'],:waggoner => 'orig',:chart => ['log','csv'],:astrolabe => false}
|
|
390
403
|
# make_orig = CsvPirate.new(capn)
|
|
391
404
|
# make_orig.hoist_mainstay
|
|
392
405
|
# make_orig.weigh_anchor
|
|
393
406
|
#
|
|
394
|
-
# first_mate = {:grub => 'account',:booty => ["id","number","name","created_at"],:waggoner => 'fake',:chart => 'log
|
|
407
|
+
# first_mate = {:grub => 'account',:booty => ["id","number","name","created_at"],:waggoner => 'fake',:chart => ['log','csv']}
|
|
395
408
|
# OR
|
|
396
409
|
# # for same class, we re-use the object loaded from first CSV and make the booty [method] calls on it
|
|
397
|
-
# first_mate = {:grub => User,:booty => ["id","login","visits_count"],:waggoner => 'fake',:chart => 'log
|
|
410
|
+
# first_mate = {:grub => User,:booty => ["id","login","visits_count"],:waggoner => 'fake',:chart => ['log','csv']}
|
|
398
411
|
# OR
|
|
399
|
-
# first_mate = {:grub => Account,:spyglasses => 'id',:swag=>'user_id',:booty => ["id","name","number"],:waggoner => 'fake',:chart => 'log
|
|
412
|
+
# first_mate = {:grub => Account,:spyglasses => 'id',:swag=>'user_id',:booty => ["id","name","number"],:waggoner => 'fake',:chart => ['log','csv']}
|
|
400
413
|
# AND
|
|
401
|
-
# capn = {:grub => User,:spyglasses => 'login',:swag => 1,:waggoner => 'orig',:chart => 'log
|
|
414
|
+
# capn = {:grub => User,:spyglasses => 'login',:swag => 1,:waggoner => 'orig',:chart => ['log','csv'],:astrolabe => true}
|
|
402
415
|
# after_mutiny = CsvPirate.mutiny(capn, first_mate)
|
|
403
416
|
#
|
|
404
417
|
def self.mutiny(capn, first_mate)
|
|
@@ -6,7 +6,7 @@ module NinthBit
|
|
|
6
6
|
def has_csv_pirate_ship(options = {})
|
|
7
7
|
raise ArgumentError, "must provide required options" if options.blank?
|
|
8
8
|
|
|
9
|
-
options[:chart] ||= 'log
|
|
9
|
+
options[:chart] ||= ['log','csv']
|
|
10
10
|
options[:aft] ||= '.csv'
|
|
11
11
|
options[:gibbet] ||= '.export'
|
|
12
12
|
#Needs to be defined at runtime, doesn't make sense here
|
|
@@ -30,7 +30,8 @@ module NinthBit
|
|
|
30
30
|
raise ArgumentError, ":mop is #{options[:mop].inspect}, but must be one of #{CsvPirate::MOP_HEADS.inspect}" unless CsvPirate::MOP_HEADS.include?(options[:mop])
|
|
31
31
|
raise ArgumentError, ":gibbet is #{options[:gibbet].inspect}, and does not contain a '.' character, which is required for iterative filenames" if options[:gibbet].nil? || !options[:gibbet].include?('.')
|
|
32
32
|
raise ArgumentError, ":waggoner is #{options[:waggoner].inspect}, and must be a string at least one character long" if options[:waggoner].nil? || options[:waggoner].length < 1
|
|
33
|
-
raise ArgumentError, ":booty is #{options[:booty].inspect}, and must be an array of methods to call on a class for CSV data" if options[:booty].nil? || options[:booty].empty?
|
|
33
|
+
raise ArgumentError, ":booty is #{options[:booty].inspect}, and must be an array of methods to call on a class for CSV data" if options[:booty].nil? || !options[:booty].is_a?(Array) || options[:booty].empty?
|
|
34
|
+
raise ArgumentError, ":chart is #{options[:chart].inspect}, and must be an array of directory names, which will become the filepath for the csv file" if options[:chart].nil? || !options[:chart].is_a?(Array) || options[:chart].empty?
|
|
34
35
|
|
|
35
36
|
extend ClassMethods unless (class << self; included_modules; end).include?(ClassMethods)
|
|
36
37
|
|