class CsvPirate::TheCapn
Constants
- BOOKIE
- BRIGANTINE_OPTIONS
- CSV_CLASS
- MOP_HEADS
Attributes
These are the booty of the CSV Should be methods/columns on the swag also used to create the figurehead (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 =>‘_’
default is false The array that gets built as we write the CSV… could be useful?
spyglasses is only used with grub, not swag
Must provide swag or grub (not both)
Public Class Methods
Sink other ships! Or run a block of code on each row of a CSV
# 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
# 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
if this is your booty: {:booty => [
:id, {:region => {:country => :name }, :state => :name }, :name
]} so nested_hash = {:region => {:country => :name }, :state => :name }
# 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
!!!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)
# 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
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
# 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
verbosity on a scale of 0 - 3 (0=:none, 1=:error, 2=:info, 3=:debug, 0 being no screen output, 1 is default
# File lib/csv_pirate/the_capn.rb, line 683 def self.parlance(level = 1) self.parlay.is_a?(Numeric) && self.parlay >= level end
Used to read any loot found by any pirate
# 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
Public Instance Methods
# 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
# 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
This is the hardest working method. Get your shovels!
# 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
# File lib/csv_pirate/the_capn.rb, line 397 def find_aye(columns) "find_by_#{columns.join('_and_')}".to_sym end
# 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
# File lib/csv_pirate/the_capn.rb, line 427 def flies Dir.entries(self.traverse_board).select {|x| x.match(self.unfurl)}.sort end
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)!
# 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
# 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
Grab an old CSV dump (first or last)
# File lib/csv_pirate/the_capn.rb, line 422 def old_csv_dump(brig) file = self.flies.send(brig) "#{self.traverse_board}#{file}" end
complete file path
# 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
# 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
Takes a potentially nested hash element of a booty array and turns it into a string for a column header
hash = {:a => {:b => {:c => {:d => {"e" => "fghi"}}}}} run_through(hash, '_') => "a_b_c_d_e_fghi" Ooooh so recursive!
# 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
# 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
# File lib/csv_pirate/the_capn.rb, line 211 def scrivener(msg) self.rhumb_lines.puts msg end
Sink your own ship! Or run a block of code on each row of the current CSV
# 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
# 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
# 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
Swabs the poop_deck
(of the brigantine) if the mop is clean. (!)
# 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
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
# 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
Regex for matching dumped CSVs
# 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
Must be done on order to rummage through the loot found by the pirate ship
# File lib/csv_pirate/the_capn.rb, line 293 def weigh_anchor TheCapn.rinse(self.brigantine) end
Protected Instance Methods
# File lib/csv_pirate/the_capn.rb, line 484 def analemma "#{self.traverse_board}#{self.merchantman}" end
Get all the files in the dir
# File lib/csv_pirate/the_capn.rb, line 512 def axe Dir.glob(self.lantern) end
returns an array of strings for CSV header based on booty
# File lib/csv_pirate/the_capn.rb, line 457 def binnacle(join_value, humanize = true) self.booty.map do |compass| string = compass.is_a?(Hash) ? self.run_through(compass, join_value) : compass.is_a?(String) ? compass : compass.is_a?(Symbol) ? compass.to_s : compass.to_s humanize ? string.to_s.gsub(/_id$/, "").gsub(/_/, " ").capitalize : string end end
create the header of the CSV (column/method names) returns an array of strings for CSV header based on blackjack
# File lib/csv_pirate/the_capn.rb, line 443 def block_and_tackle self.blackjack.map do |k,v| case k #Joining is only relevant when the booty contains a nested hash of method calls as at least one of the booty array elements #Use the booty (methods) as the column headers when :join then self.binnacle(v, false) #Use the humanized booty (methods) as the column headers when :humanize then self.binnacle(v, true) when :array then v end end.first end
File increment for next CSV to dump
# File lib/csv_pirate/the_capn.rb, line 517 def boatswain return self.swabbie unless self.swabbie.nil? highval = 0 self.axe.each do |flotsam| counter = self.filibuster(flotsam) highval = ((highval <=> counter) == 1) ? highval : counter end ".#{highval + 1}" end
# File lib/csv_pirate/the_capn.rb, line 527 def coxswain return self.swabbie unless self.swabbie.nil? ".#{Time.now.strftime("%I%M%S")}" end
# File lib/csv_pirate/the_capn.rb, line 503 def filibuster(flotsam) base = File.basename(flotsam, self.aft) index = base.rindex('.') tail = index.nil? ? nil : base[index+1,base.length] # Ensure numbers tail.nil? ? 0 : tail[/\d*/].to_i end
Sets the swabby file counter
# File lib/csv_pirate/the_capn.rb, line 533 def insult_swabbie return case self.swab when :counter self.boatswain when :timestamp self.coxswain else "" end end
# File lib/csv_pirate/the_capn.rb, line 499 def lantern "#{self.analemma}.*" end
# File lib/csv_pirate/the_capn.rb, line 480 def merchantman "#{self.waggoner}#{self.sand_glass}#{self.gibbet}" end
# File lib/csv_pirate/the_capn.rb, line 488 def north_pole "#{defined?(Rails) ? "#{Rails.root}/" : defined?(RAILS_ROOT) ? "#{RAILS_ROOT}/" : ''}" end
# File lib/csv_pirate/the_capn.rb, line 492 def northwest_passage self.chart.length.times do |i| north_star = self.north_pole + self.chart[0..i].join('/') Dir.mkdir(north_star) if Dir.glob(north_star).empty? end end
# File lib/csv_pirate/the_capn.rb, line 476 def sand_glass "#{self.chronometer.respond_to?(:strftime) ? '.' + self.chronometer.strftime("%Y%m%d") : ''}" end
The directory path to the csv
# File lib/csv_pirate/the_capn.rb, line 471 def traverse_board #If we have rails environment then we use rails root, otherwise self.chart stands on its own as a relative path "#{self.north_pole}#{self.chart.join('/')}/" end