From 795b4e4478fc422a437db787060c71a9154cee87 Mon Sep 17 00:00:00 2001 From: Andy Meneely Date: Mon, 11 Apr 2016 20:07:55 -0400 Subject: [PATCH] csv: yield to block on each cell Closes #151 Related to #145 --- docs/dsl/csv.rst | 13 +++++++++++++ docs/dsl/xlsx.rst | 15 ++++++++++++++- lib/squib/api/data.rb | 13 ++++++++++++- spec/api/api_data_spec.rb | 29 +++++++++++++++++++++++++++++ spec/data/csv/yield.csv | 3 +++ 5 files changed, 71 insertions(+), 2 deletions(-) create mode 100644 spec/data/csv/yield.csv diff --git a/docs/dsl/csv.rst b/docs/dsl/csv.rst index 190cdee..ecd54fd 100644 --- a/docs/dsl/csv.rst +++ b/docs/dsl/csv.rst @@ -44,6 +44,19 @@ col_sep CSV custom options in Ruby standard lib. All of the options in Ruby's std lib version of CSV are supported **except** ``headers`` is always ``true`` and ``converters`` is always set to ``:numeric``. See the `Ruby Docs `_ for information on the options. +Individual Pre-processing +------------------------- + +The ``xlsx`` method also takes in a block that will be executed for each cell in your data. This is useful for processing individual cells, like putting a dollar sign in front of dollars, or converting from a float to an integer. The value of the block will be what is assigned to that cell. For example:: + + resource_data = Squib.csv(file: 'sample.xlsx') do |header, value| + case header + when 'Cost' + "$#{value}k" # e.g. "3" becomes "$3k" + else + value # always return the original value if you didn't do anything to it + end + end Examples -------- diff --git a/docs/dsl/xlsx.rst b/docs/dsl/xlsx.rst index 36a420a..d146e0a 100644 --- a/docs/dsl/xlsx.rst +++ b/docs/dsl/xlsx.rst @@ -9,7 +9,6 @@ The ``xlsx`` method is a member of ``Squib::Deck``, but it is also available out Squib::Deck.new(cards: data['name'].size) do end - Options ------- @@ -33,5 +32,19 @@ explode Quantity explosion will be applied to the column this name. For example, rows in the csv with a ``'qty'`` of 3 will be duplicated 3 times. +Individual Pre-processing +------------------------- + +The ``xlsx`` method also takes in a block that will be executed for each cell in your data. This is useful for processing individual cells, like putting a dollar sign in front of dollars, or converting from a float to an integer. The value of the block will be what is assigned to that cell. For example:: + + resource_data = Squib.xlsx(file: 'sample.xlsx') do |header, value| + case header + when 'Cost' + "$#{value}k" # e.g. "3" becomes "$3k" + else + value # always return the original value if you didn't do anything to it + end + end + Examples -------- diff --git a/lib/squib/api/data.rb b/lib/squib/api/data.rb index 99ca938..c2f286b 100644 --- a/lib/squib/api/data.rb +++ b/lib/squib/api/data.rb @@ -32,6 +32,7 @@ module Squib # DSL method. See http://squib.readthedocs.org def csv(opts = {}) + # TODO refactor all this out to separate methods, and its own class import = Args::Import.new.load!(opts) file = Args::InputFile.new(file: 'deck.csv').load!(opts).file[0] data = opts.key?(:data) ? opts[:data] : File.read(file) @@ -47,10 +48,20 @@ module Squib if import.strip? new_hash = Hash.new hash.each do |header, col| - new_hash[header] = col.map { |str| str = str.strip if str.respond_to?(:strip); str } + new_hash[header] = col.map do |str| + str = str.strip if str.respond_to?(:strip) + str + end end hash = new_hash end + if block_given? + hash.each do |header, col| + col.map! do |val| + yield(header, val) + end + end + end return explode_quantities(hash, import.explode) end module_function :csv diff --git a/spec/api/api_data_spec.rb b/spec/api/api_data_spec.rb index 5aa394a..15ab0d9 100644 --- a/spec/api/api_data_spec.rb +++ b/spec/api/api_data_spec.rb @@ -76,6 +76,35 @@ describe Squib::Deck do }) end + it 'yields to block when given' do + data = Squib.csv(file: csv_file('basic.csv')) do |header, value| + case header + when 'h1' + value * 2 + else + 'ha' + end + end + expect(data).to eq({ + 'h1' => [2, 6], + 'h2' => %w(ha ha), + }) + end + + it 'replaces newlines whenever its a string' do + data = Squib.csv(file: csv_file('yield.csv')) do |header, value| + if value.respond_to? :gsub + value.gsub '%n', "\n" + else + value + end + end + expect(data).to eq({ + 'a' => ["foo\nbar", 1], + 'b' => [1, "blah\n"], + }) + end + end context '#xlsx' do diff --git a/spec/data/csv/yield.csv b/spec/data/csv/yield.csv new file mode 100644 index 0000000..611b013 --- /dev/null +++ b/spec/data/csv/yield.csv @@ -0,0 +1,3 @@ +a,b +foo%nbar,1 +1,blah%n