Class: CsvPirate::TheCapn

Inherits:
Object
  • Object
show all
Defined in:
lib/csv_pirate/the_capn.rb

Constant Summary

BOOKIE =
[:counter, :timestamp, :none]
MOP_HEADS =
[:clean, :dirty]
BRIGANTINE_OPTIONS =
[:first, :last]
CSV_CLASS =
(CSV) ? CSV : FasterCSV)

Class Attribute Summary collapse

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(*args) ⇒ TheCapn

CsvPirate only works for commissions of swag OR grub! :swag the ARrr collection of swag to work on (optional) :grub the ARrr class that the spyglasses will be used on (optional) :spyglasses named scopes in your model that will refine the rows in the CSV according to conditions of the spyglasses,

and order them according to the order of the spyglasses (optional)

:booty booty (columns/methods) on your model that you want printed in the CSV, also used to create the figurehead (CSV header) :chart array of directory names (relative to rails root if using rails) which will be the filepath where you want to hide your loot :wagonner name of document where you will give detailed descriptions of the loot :aft filename extention ('.csv') :shrouds CSV column separator, default is ','. For tsv, tab-delimited, “t” :chronometer keeps track of when you hunt for treasure, can be false if you don't want to keep track. :gibbet filename spacer after the date, and before the iterative counter/timestamp. MuST contain a '.' :swab can be :counter, :timestamp, or :none

:counter - default, each successive run will create a new file using a counter
:timestamp - each successive run will create a new file using a HHMMSS time stamp
:none - no iterative file naming convention, just use waggoner, aft and gibbet

: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

:clean - do not use :counter or :timestamp, and instead overwrite the file
:dirty - do not use :counter, or :timestamp, or :overwrite.  Just keep adding on.

: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)? :blackjack Specify how you want your CSV header

{:join => '-'}    joins the method names called to get hte data for that column with '_' underscores.
{:humanize =>'-'} first joins as above, then humanizes the string
{:array => ['col1',col2','col3'] Uses the column names provided.  If the array provided is too short defaults to :humanize =>'_'

See README for examples

Raises:

  • (ArgumentError)


79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
# File 'lib/csv_pirate/the_capn.rb', line 79

def initialize(*args)
  raise ArgumentError, "must provide required options" if args.nil?

  @swag = args.first[:swag]
  @grub = args.first[:grub]

  # if they provide both
  raise ArgumentError, "must provide either :swag or :grub, not both" if !self.swag.nil? && !self.grub.nil?
  # if they provide neither
  raise ArgumentError, "must provide either :swag or :grub" if self.swag.nil? && self.grub.nil?

  @swab = args.first[:swab] || :counter
  raise ArgumentError, ":swab is #{self.swab.inspect}, but must be one of #{TheCapn::BOOKIE.inspect}" unless TheCapn::BOOKIE.include?(self.swab)

  @mop = args.first[:mop] || :clean
  raise ArgumentError, ":mop is #{self.mop.inspect}, but must be one of #{TheCapn::MOP_HEADS.inspect}" unless TheCapn::MOP_HEADS.include?(self.mop)

  @gibbet = args.first[:gibbet] || '.export'
  raise ArgumentError, ":gibbet is #{self.gibbet.inspect}, and does not contain a '.' character, which is required when using iterative filenames (set :swab => :none to turn off iterative filenames)" if self.swab != :none && (self.gibbet.nil? || !self.gibbet.include?('.'))

  @waggoner = args.first[:waggoner] || "#{self.grub || self.swag}"
  raise ArgumentError, ":waggoner is #{self.waggoner.inspect}, and must be a string at least one character long" if self.waggoner.nil? || self.waggoner.length < 1

  # Not checking if empty here because PirateShip will send [] if the database is unavailable, to allow tasks like rake db:create to run
  @booty = args.first[:booty] || [] # would like to use Class#instance_variables for generic classes
  raise ArgumentError, ":booty is #{self.booty.inspect}, and must be an array of methods to call on a class for CSV data" if self.booty.nil? || !self.booty.is_a?(Array)

  @chart = args.first[:chart] || ['log','csv']
  raise ArgumentError, ":chart is #{self.chart.inspect}, and must be an array of directory names, which will become the filepath for the csv file" if self.chart.nil? || !self.chart.is_a?(Array) || self.chart.empty?

  @aft = args.first[:aft] || '.csv'
  @chronometer = args.first[:chronometer] == false ? false : (args.first[:chronometer] || Date.today)

  @spyglasses = (args.first[:spyglasses] || (self.respond_to?(:all) ? [:all] : nil)) if self.grub

  @shrouds = args.first[:shrouds] || ','  # for tsv, tab-delimited, "\t"
  raise ArgumentError, ":shrouds is #{self.shrouds.inspect}, and must be a string (e.g. ',' or '\t'), which will be used as the delimeter for the csv file" if self.shrouds.nil? || !self.shrouds.is_a?(String)

  @astrolabe = args.first[:astrolabe] || false

  @bury_treasure = args.first[:bury_treasure] || false
  @buried_treasure = []

  #does not rely on rails humanize!
  @blackjack = args.first[:blackjack] || {:humanize => '_'}

  #Make sure the header array is the same length as the booty columns
  if self.blackjack.keys.first == :array && (self.blackjack.values.first.length != self.booty.length)
    @blackjack = {:join => '_'}
    puts "Warning: :blackjack reset to {:join => '_'} because the length of the :booty is different than the length of the array provided to :blackjack" if TheCapn.parlance(2)
  end

  @pinnacle = self.block_and_tackle

  # Initialize doesn't write anything to a CSV,
  #   but does create the traverse_board (file) and opens it for reading / writing
  self.northwest_passage unless self.astrolabe

  # This will contain the text of the csv from this particular execution
  @maroon = ""

  # Once the traverse_board (dir) exists, then check if the rhumb_lines (file) already exists, and set our rhumb_lines counter
  @swabbie = self.insult_swabbie

  @brigantine = self.poop_deck(args.first[:brigantine])

  @nocturnal = File.basename(self.brigantine)

  # Then open the rhumb_lines
  self.rhumb_lines = File.open(File.expand_path(self.brigantine),self.astrolabe ? "r" : "a")
end

Class Attribute Details

.parlayObject

verbosity on a scale of 0 - 3 (0=:none, 1=:error, 2=:info, 3=:debug, 0 being no screen output, 1 is default



50
51
52
# File 'lib/csv_pirate/the_capn.rb', line 50

def parlay
  @parlay
end

Instance Attribute Details

#aftObject

Returns the value of attribute aft



11
12
13
# File 'lib/csv_pirate/the_capn.rb', line 11

def aft
  @aft
end

#astrolabeObject

when true then read only CsvPirate instance for loading of CSVs



33
34
35
# File 'lib/csv_pirate/the_capn.rb', line 33

def astrolabe
  @astrolabe
end

#blackjackObject

Returns the value of attribute blackjack



42
43
44
# File 'lib/csv_pirate/the_capn.rb', line 42

def blackjack
  @blackjack
end

#bootyObject

These are the booty of the CSV Should be methods/columns on the swag also used to create the figurehead (CSV header)



24
25
26
# File 'lib/csv_pirate/the_capn.rb', line 24

def booty
  @booty
end

#brigantineObject

default is :counter default is :clean (only has an effect if :swab is :none) since overwriting is irrelevant for a new file value of the counter / timestamp text of csv basename of the filepath (i.e. filename) Hash: Specify how you want your CSV header

{:join => '-'}    joins the method names called to get hte data for that column with '_' underscores.
{:humanize => '-'} first joins as above, then humanizes the string
{:array => ['col1',col2','col3'] Uses the column names provided in the array.  If the array provided is too short defaults to :humanize =>'_'


47
48
49
# File 'lib/csv_pirate/the_capn.rb', line 47

def brigantine
  @brigantine
end

#buried_treasureObject

The array that gets built as we write the CSV… could be useful?



29
30
31
# File 'lib/csv_pirate/the_capn.rb', line 29

def buried_treasure
  @buried_treasure
end

#bury_treasureObject

Returns the value of attribute bury_treasure



26
27
28
# File 'lib/csv_pirate/the_capn.rb', line 26

def bury_treasure
  @bury_treasure
end

#chartObject

Returns the value of attribute chart



10
11
12
# File 'lib/csv_pirate/the_capn.rb', line 10

def chart
  @chart
end

#chronometerObject

First part of filename directory, default is (['log','csv']) extension, default is ('.csv') part of the filename after waggoner and date, before swabbie and aft Date object or false



13
14
15
# File 'lib/csv_pirate/the_capn.rb', line 13

def chronometer
  @chronometer
end

#gibbetObject

Returns the value of attribute gibbet



12
13
14
# File 'lib/csv_pirate/the_capn.rb', line 12

def gibbet
  @gibbet
end

#grubObject

Array of objects Class



17
18
19
# File 'lib/csv_pirate/the_capn.rb', line 17

def grub
  @grub
end

#maroonObject

Returns the value of attribute maroon



40
41
42
# File 'lib/csv_pirate/the_capn.rb', line 40

def maroon
  @maroon
end

#mopObject

Returns the value of attribute mop



38
39
40
# File 'lib/csv_pirate/the_capn.rb', line 38

def mop
  @mop
end

#nocturnalObject

Returns the value of attribute nocturnal



41
42
43
# File 'lib/csv_pirate/the_capn.rb', line 41

def nocturnal
  @nocturnal
end

#pinnacleObject

the complete file path an array of strings for CSV header based on blackjack



48
49
50
# File 'lib/csv_pirate/the_capn.rb', line 48

def pinnacle
  @pinnacle
end

#rhumb_linesObject

the file object to write the CSV lines to



31
32
33
# File 'lib/csv_pirate/the_capn.rb', line 31

def rhumb_lines
  @rhumb_lines
end

#shroudsObject

CSV column separator



35
36
37
# File 'lib/csv_pirate/the_capn.rb', line 35

def shrouds
  @shrouds
end

#spyglassesObject

spyglasses is only used with grub, not swag



19
20
21
# File 'lib/csv_pirate/the_capn.rb', line 19

def spyglasses
  @spyglasses
end

#swabObject

Returns the value of attribute swab



37
38
39
# File 'lib/csv_pirate/the_capn.rb', line 37

def swab
  @swab
end

#swabbieObject

Returns the value of attribute swabbie



39
40
41
# File 'lib/csv_pirate/the_capn.rb', line 39

def swabbie
  @swabbie
end

#swagObject

Must provide swag or grub (not both)



16
17
18
# File 'lib/csv_pirate/the_capn.rb', line 16

def swag
  @swag
end

#waggonerObject

Returns the value of attribute waggoner



9
10
11
# File 'lib/csv_pirate/the_capn.rb', line 9

def waggoner
  @waggoner
end

Class Method Details

.broadside(galley, &block) ⇒ Object

Sink other ships! Or run a block of code on each row of a CSV



589
590
591
592
593
594
# File 'lib/csv_pirate/the_capn.rb', line 589

def self.broadside(galley, &block)
  return false unless block_given?
  CSV_CLASS.foreach(galley, {:headers => :first_row, :return_headers => false}) do |gun|
    yield gun
  end
end

.create(*args) ⇒ Object



151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
# File 'lib/csv_pirate/the_capn.rb', line 151

def self.create(*args)
  csv_pirate = TheCapn.new({
    :chart => args.first[:chart],
    :aft => args.first[:aft],
    :gibbet => args.first[:gibbet],
    :chronometer => args.first[:chronometer],
    :waggoner => args.first[:waggoner],
    :swag => args.first[:swag],
    :swab => args.first[:swab],
    :shrouds => args.first[:shrouds],
    :mop => args.first[:mop],
    :grub => args.first[:grub],
    :spyglasses => args.first[:spyglasses],
    :booty => args.first[:booty],
    :astrolabe => args.first[:astrolabe],
    :blackjack => args.first[:blackjack],
    :bury_treasure => args.first[:bury_treasure]
  })
  csv_pirate.hoist_mainstay()
  csv_pirate
end

.marlinespike(spoils, navigation) ⇒ Object

if this is your booty: {:booty => [

:id,
{:region => {:country => :name }, :state => :name },
:name

]} so nested_hash = {:region => {:country => :name }, :state => :name }



557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
# File 'lib/csv_pirate/the_capn.rb', line 557

def self.marlinespike(spoils, navigation)
  navigation.map do |east,west|
    # BJM:
    if east.is_a?(Array)
      spoils = spoils.send(east[0].to_sym, *east[1..-1] )
    else
      spoils = spoils.send(east.to_sym)
    end
    unless spoils.nil?
      if west.is_a?(Hash)
        # Recursive madness is here!
        spoils = TheCapn.marlinespike(spoils, west)
      elsif west.is_a?(Array)
        spoils << spoils.send(west[0].to_sym, *west[1..-1] )
      else
        spoils = spoils.send(west.to_sym)
      end
    end
    spoils
  end.compact.join(' - ')
end

.mutiny(capn, first_mate) ⇒ Object

!!!EXPERIMENTAL!!!

During a mutiny things are a little different! Essentially you are using an existing CSV to drive queries to create a second CSV cased on the first The capn hash is:

:grub       => is the class on which to make booty [method] calls
:swag       => column index in CSV (0th, 1st, 2nd, etc. column?)
               (swag OR spyglasses can be specified, but code defers to swag if provided)
:spyglasses => is the column to load ("find_by_#{booty}") the ARrr object for each row on the first CSV
               (swag OR spyglasses can be specified, but code defers to swag if provided)
:waggoner   => where the capn's loot was stashed (filename)
:chart      => array of directory names where capn's waggoner is located
:astrolabe  => true (file is opened at top of file in read only mode when true)

The first_mate hash is:

:grub       => is the class on which to make booty [method] calls, or
                 is a method (as a string) we call to get from the object loaded by capn,
                 to the object on which we'll make the first_mate booty [method] calls, or nil, if same object
:swag       => is the method to call on first CSV row's object to find second CSV row's object (if grub is a class)
:spyglasses => is the column to load ("find_by_#{booty}") the ARrr object for each row on the second CSV (if grub is a class)
:booty      => is the methods to call on the ARrr object for each row on the second CSV
:waggoner   => where to stash the first mate's loot (filename)
:chart      => array of directory names where first mate's waggoner is located
:astrolabe  => false (false is the default for astrolabe, so we could leave it off the first_mate)

Example:

 capn      = {:grub => User,:spyglasses => [:inactive],:booty => ['id','login','status'],:waggoner => 'orig',:chart => ['log','csv'],:astrolabe => false}
 make_orig = CsvPirate.new(capn)
 make_orig.hoist_mainstay
 make_orig.weigh_anchor

 first_mate = {:grub => 'account',:booty => ["id","number","name","created_at"],:waggoner => 'fake',:chart => ['log','csv']}
OR
 # for same class, we re-use the object loaded from first CSV and make the booty [method] calls on it
 first_mate = {:grub => User,:booty => ["id","login","visits_count"],:waggoner => 'fake',:chart => ['log','csv']}
OR
 first_mate = {:grub => Account,:spyglasses => 'id',:swag=>'user_id',:booty => ["id","name","number"],:waggoner => 'fake',:chart => ['log','csv']}
AND
 capn       = {:grub => User,:spyglasses => 'login',:swag => 1,:waggoner => 'orig',:chart => ['log','csv'],:astrolabe => true}
 after_mutiny = CsvPirate.mutiny(capn, first_mate)


636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
# File 'lib/csv_pirate/the_capn.rb', line 636

def self.mutiny(capn, first_mate)
  carrack = TheCapn.new(capn)
  cutthroat = TheCapn.new(first_mate)

  cutthroat.figurehead

  carrack.scuttle do |cutlass|
    puts "CUTLASS: #{cutlass.inspect}" if TheCapn.parlance(2)
    puts "CARRACK.SWAG: #{carrack.swag.inspect}" if TheCapn.parlance(2)
    backstaff = cutlass[carrack.swag] || cutlass["#{carrack.spyglasses}"]
    puts "BACKSTAFF: #{backstaff}" if TheCapn.parlance(2)
    puts "CARRACK.SPYGLASSES: #{carrack.spyglasses.inspect}" if TheCapn.parlance(2)
    gully = carrack.grub.send("find_by_#{carrack.spyglasses}".to_sym, backstaff)
    puts "GULLY: #{gully.inspect}" if TheCapn.parlance(2)
    if gully
      flotsam = cutthroat.grub.is_a?(String) ?
        gully.send(cutthroat.grub.to_sym) :
        cutthroat.grub.is_a?(Symbol) ?
          gully.send(cutthroat.grub) :
          cutthroat.grub.class == carrack.grub.class ?
            gully :
            cutthroat.grub.class == Class ?
              cutthroat.grub.send("find_by_#{cutthroat.swag}", gully.send(cutthroat.spyglasses)) :
              nil
      puts "FLOTSAM: #{flotsam.inspect}" if TheCapn.parlance(2)
      if flotsam
        plunder = cutthroat.prize(flotsam)
        cutthroat.buried_treasure << plunder
        cutthroat.scrivener(plunder.map {|bulkhead| "#{bulkhead}"}.join(','))
      else
        puts "Unable to locate: #{cutthroat.grub} related to #{carrack.grub}.#{carrack.spyglasses} '#{gully.send(carrack.spyglasses)}'" if TheCapn.parlance(1)
      end
    else
      puts "Unable to locate: #{carrack.grub}.#{carrack.spyglasses} '#{gully.send(carrack.spyglasses)}'" if TheCapn.parlance(1)
    end
  end

  carrack.rhumb_lines.close
  cutthroat.rhumb_lines.close

  cutthroat.jolly_roger

  # returns the array that is created before exporting it to CSV
  return cutthroat
end

.parlance(level = 1) ⇒ Object

verbosity on a scale of 0 - 3 (0=:none, 1=:error, 2=:info, 3=:debug, 0 being no screen output, 1 is default



683
684
685
# File 'lib/csv_pirate/the_capn.rb', line 683

def self.parlance(level = 1)
  self.parlay.is_a?(Numeric) && self.parlay >= level
end

.rinse(quarterdeck) ⇒ Object

Used to read any loot found by any pirate



580
581
582
583
584
585
586
# File 'lib/csv_pirate/the_capn.rb', line 580

def self.rinse(quarterdeck)
  File.open(File.expand_path(quarterdeck), "r") do |bucket_line|
    bucket_line.each_line do |bucket|
      puts bucket
    end
  end
end

Instance Method Details

#data_hash_from_row(row, exclude_id = true, exclude_timestamps = true) ⇒ Object



407
408
409
410
411
412
413
414
415
416
417
418
419
# File 'lib/csv_pirate/the_capn.rb', line 407

def data_hash_from_row(row, exclude_id = true, exclude_timestamps = true)
  plunder = {}
  method_check = self.grub.instance_methods - Object.methods
  method_check = method_check.select {|x| "#{x}" =~ /=$/}
  my_booty = self.booty.reject {|x| x.is_a?(Hash)}
  my_booty = exclude_id ? my_booty.reject {|x| a = x.to_sym; [:id, :ID,:dbid, :DBID, :db_id, :DB_ID].include?(a)} : self.booty
  my_booty = exclude_timestamps ? my_booty.reject {|x| a = x.to_sym; [:created_at, :updated_at, :created_on, :updated_on].include?(a)} : self.booty
  my_booty = my_booty.select {|x| method_check.include?("#{x}=".to_sym)} if method_check
  my_booty.each do |method|
    plunder = plunder.merge({method => row[self.pinnacle[self.booty.index(method)]]})
  end
  plunder
end

#dead_mans_chestObject



232
233
234
235
236
237
238
# File 'lib/csv_pirate/the_capn.rb', line 232

def dead_mans_chest
  self.maroon = CSV_CLASS.generate(:col_sep => self.shrouds) do |csv|
    self.sounding(csv)
  end
  self.scrivener(self.maroon)
  self.maroon
end

#dig_for_treasure(&block) ⇒ Object

This is the hardest working method. Get your shovels!



178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
# File 'lib/csv_pirate/the_capn.rb', line 178

def dig_for_treasure(&block)
  return false unless block_given?

  if !grub.nil?
    self.swag = grub
    spyglasses.each {|x| self.swag = self.swag.send(x) }
  end

  treasure_chest = self.swag.map do |spoils|
    self.prize(spoils)
  end

  treasure_chest.each do |loot|
    yield loot
  end
end

#find_aye(columns) ⇒ Object



397
398
399
# File 'lib/csv_pirate/the_capn.rb', line 397

def find_aye(columns)
  "find_by_#{columns.join('_and_')}".to_sym
end

#find_aye_arr(data_hash, columns) ⇒ Object



401
402
403
404
405
# File 'lib/csv_pirate/the_capn.rb', line 401

def find_aye_arr(data_hash, columns)
  columns.map do |col|
    data_hash[col.to_s]
  end
end

#fliesObject



427
428
429
# File 'lib/csv_pirate/the_capn.rb', line 427

def flies
  Dir.entries(self.traverse_board).select {|x| x.match(self.unfurl)}.sort
end

#hoist_mainstayObject

Sail through your db looking for buried treasure! Creates the CSV file and returns the text of the CSV

  • restricted to loot that can be seen through spyglasses (if provided)!



218
219
220
221
222
223
224
225
226
227
228
229
230
# File 'lib/csv_pirate/the_capn.rb', line 218

def hoist_mainstay

  self.swab_poop_deck

  self.dead_mans_chest

  self.rhumb_lines.close

  self.jolly_roger if TheCapn.parlay && TheCapn.parlance(1)

  # returns the text of this CSV export
  return self.maroon
end

#jolly_rogerObject



240
241
242
243
244
245
246
247
248
249
# File 'lib/csv_pirate/the_capn.rb', line 240

def jolly_roger
  if self.bury_treasure
    if self.buried_treasure.is_a?(Array)
      puts "Found #{self.buried_treasure.length} deniers buried here: '#{self.brigantine}'" if TheCapn.parlay && TheCapn.parlance(1)
      puts "You must weigh_anchor to review your plunder!" if TheCapn.parlay && TheCapn.parlance(1)
    else
      puts "Failed to locate treasure" if TheCapn.parlay && TheCapn.parlance(1)
    end
  end
end

#old_csv_dump(brig) ⇒ Object

Grab an old CSV dump (first or last)



422
423
424
425
# File 'lib/csv_pirate/the_capn.rb', line 422

def old_csv_dump(brig)
  file = self.flies.send(brig)
  "#{self.traverse_board}#{file}"
end

#poop_deck(brig) ⇒ Object

complete file path



277
278
279
280
281
282
283
284
285
# File 'lib/csv_pirate/the_capn.rb', line 277

def poop_deck(brig)
  if BRIGANTINE_OPTIONS.include?(brig) && !self.flies.empty?
    self.old_csv_dump(brig)
  elsif brig.is_a?(String)
    "#{self.analemma}#{brig}"
  else
    "#{self.analemma}#{self.swabbie}#{self.aft}"
  end
end

#prize(spoils) ⇒ Object



195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
# File 'lib/csv_pirate/the_capn.rb', line 195

def prize(spoils)
  gold_doubloons = []
  self.booty.each do |plunder|
    # Check for nestedness
    if plunder.is_a?(Hash)
      gold_doubloons << TheCapn.marlinespike(spoils, plunder)
    # BJM: if array, assume they are args to be sent along with the function
    elsif plunder.is_a?(Array)
      gold_doubloons << spoils.send(plunder[0].to_sym, *plunder[1..-1] )
    else
      gold_doubloons << spoils.send(plunder.to_sym)
    end
  end
  gold_doubloons
end

#run_through(hash, join_value) ⇒ Object

Takes a potentially nested hash element of a booty array and turns it into a string for a column header hash = => {:b => {:c => {:d => {“e” => “fghi”}}}} run_through(hash, '_')

> “a_b_c_d_e_fghi”

Ooooh so recursive!



266
267
268
269
270
271
272
273
274
# File 'lib/csv_pirate/the_capn.rb', line 266

def run_through(hash, join_value)
  hash.map do |k,v|
    if v.is_a?(Hash)
      [k,run_through(v, join_value)].join(join_value)
    else #works for Symbols and Strings
      [k,v].join(join_value)
    end
  end.first
end

#save_object(obj, data_hash) ⇒ Object



380
381
382
383
384
385
386
387
# File 'lib/csv_pirate/the_capn.rb', line 380

def save_object(obj, data_hash)
  data_hash.each do |k,v|
    obj.send("#{k}=".to_sym, v)
  end
  unless obj.save(false)
    puts "Save Failed: #{obj.inspect}" if TheCapn.parlance(1)
  end
end

#scrivener(msg) ⇒ Object



211
212
213
# File 'lib/csv_pirate/the_capn.rb', line 211

def scrivener(msg)
  self.rhumb_lines.puts msg
end

#scuttle(&block) ⇒ Object

Sink your own ship! Or run a block of code on each row of the current CSV



298
299
300
301
302
303
# File 'lib/csv_pirate/the_capn.rb', line 298

def scuttle(&block)
  return false unless block_given?
  TheCapn.broadside(self.brigantine) do |careen|
    yield careen
  end
end

#send_aye(data_hash, columns) ⇒ Object



389
390
391
392
393
394
395
# File 'lib/csv_pirate/the_capn.rb', line 389

def send_aye(data_hash, columns)
  obj = self.grub.send(self.find_aye(columns), self.find_aye_arr(data_hash, columns))
  if obj
    puts "#{self.grub}.#{find_aye(columns)}(#{self.find_aye_arr(data_hash, columns).inspect}): found id = #{obj.id}" if TheCapn.parlance(2)
  end
  obj
end

#sounding(csv) ⇒ Object



251
252
253
254
255
256
257
258
259
# File 'lib/csv_pirate/the_capn.rb', line 251

def sounding(csv)
  csv << self.block_and_tackle
  # create the data for the csv
  self.dig_for_treasure do |treasure|
    moidore = treasure.map {|x| "#{x}"}
    csv << moidore # |x| marks the spot!
    self.buried_treasure << moidore if self.bury_treasure
  end
end

#swab_poop_deckObject

Swabs the poop_deck (of the brigantine) if the mop is clean. (!)



288
289
290
# File 'lib/csv_pirate/the_capn.rb', line 288

def swab_poop_deck
  self.rhumb_lines.truncate(0) if self.swab == :none && self.mop == :clean && File.size(self.brigantine) > 0
end

#to_memory(permanence = {:new => :new}, exclude_id = true, exclude_timestamps = true) ⇒ Object

permanence can be any of:

{:new => :new} - only calls the initializer with data hash for each row to instantiate objects (useful with any vanilla Ruby Class)
{:new => :save} - calls the initializer with the data hash for each row and then calls save on each (useful with ActiveRecord)
{:new => :create} - calls a create method with the data hash for each row (useful with ActiveRecord)
{:find_or_new => [column names for find_by]} - see below (returns only the new objects
{:find_or_save => [column names for find_by]} - see below (returns all found or saved objects)
{:find_or_create => [column names for find_by]} - looks for existing objects using find_by_#{columns.join('_and_')}, (returns all found or created objects)
    and if not found creates a new object.
    The difference between the new, save and create versions are the same as the various :new hashes above.
{:update_or_new => [column names for find_by]} - see below (returns only the new objects)
{:update_or_save => [column names for find_by]} - see below (returns all updated or saved objects)
{:update_or_create => [column names for find_by]} - looks for existing objects using find_by_#{columns.join('_and_')} , (returns all updated or created objects)
    and updates them with the data hash form the csv row, otherwise creates a new object.

TODO: This is a nasty method. Just a quick hack to GTD. Needs to be rethought and refactored. –pboling



319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
# File 'lib/csv_pirate/the_capn.rb', line 319

def to_memory(permanence = {:new => :new}, exclude_id = true, exclude_timestamps = true)
  return nil unless self.grub
  buccaneers = []
  self.scuttle do |row|
    data_hash = self.data_hash_from_row(row, exclude_id, exclude_timestamps)
    case permanence
      when {:new => :new} then
        buccaneers << self.grub.new(data_hash)
      when {:new => :save} then
        obj = self.grub.new(data_hash)
        buccaneers << obj.save(false)
      when {:new => :create} then
        buccaneers << self.grub.create(data_hash)
    else
      if permanence[:find_or_new]
        obj = self.send_aye(data_hash, permanence[:find_or_new])
        buccaneers << self.grub.new(data_hash) if obj.nil?
      elsif permanence[:find_or_save]
        obj = self.send_aye(data_hash, permanence[:find_or_save])
        if obj.nil?
          obj = self.grub.new(data_hash)
          obj.save(false) if obj.respond_to?(:save)
        end
        buccaneers << obj
      elsif permanence[:find_or_create]
        obj = self.send_aye(data_hash, permanence[:find_or_create])
        if obj.nil?
          self.grub.create(data_hash)
        end
        buccaneers << obj
      elsif permanence[:update_or_new]
        obj = self.send_aye(data_hash, permanence[:update_or_new])
        if obj.nil?
          obj = self.grub.new(data_hash)
        else
          self.save_object(obj, data_hash)
        end
        buccaneers << obj
      elsif permanence[:update_or_save]
        obj = self.send_aye(data_hash, permanence[:update_or_save])
        if obj.nil?
          obj = self.grub.new(data_hash)
          obj.save(false)
        else
          self.save_object(obj, data_hash)
        end
        buccaneers << obj
      elsif permanence[:update_or_create]
        obj = self.send_aye(data_hash, permanence[:update_or_create])
        if obj.nil?
          obj = self.grub.create(data_hash)
        else
          self.save_object(obj, data_hash)
        end
        buccaneers << obj
      end
    end
  end
  buccaneers
end

#unfurlObject

Regex for matching dumped CSVs



432
433
434
435
436
437
# File 'lib/csv_pirate/the_capn.rb', line 432

def unfurl
  wibbly = self.waggoner == '' ? '' : Regexp.escape(self.waggoner)
  timey = self.sand_glass == '' ? '' : '\.\d+'
  wimey = self.gibbet == '' ? '' : Regexp.escape(self.gibbet)
  Regexp.new("#{wibbly}#{timey}#{wimey}")
end

#weigh_anchorObject

Must be done on order to rummage through the loot found by the pirate ship



293
294
295
# File 'lib/csv_pirate/the_capn.rb', line 293

def weigh_anchor
  TheCapn.rinse(self.brigantine)
end