Skip to content

Commit

Permalink
to supports anything that responds to call (#72)
Browse files Browse the repository at this point in the history
  • Loading branch information
pcreux authored Nov 29, 2019
1 parent 1a910d9 commit 3c9d9b2
Show file tree
Hide file tree
Showing 3 changed files with 37 additions and 12 deletions.
22 changes: 21 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -187,6 +187,27 @@ Like very advanced stuff? We grant you access to the [`column`](https://github.c
end
```

Note that `to:` accepts anything that responds to call and take 1, 2 or
3 arguments.

```ruby
class ImportUserCSV
include CSVImporter

model User

column :birth_date, to: DateTransformer
column :renewal_date, to: DateTransformer
column :next_renewal_at, to: ->(value) { Time.at(value.to_i) }
end

class DateTransformer
def self.call(date)
Date.strptime(date, '%m/%d/%y')
end
end
```

Now, what if the user does not provide the email column? It's not worth
running the import, we should just reject the CSV file right away.
That's easy:
Expand All @@ -206,7 +227,6 @@ import.report.status # => :invalid_header
import.report.message # => "The following columns are required: 'email'"
```


### Update or Create

You often want to find-and-update-or-create when importing a CSV file.
Expand Down
15 changes: 8 additions & 7 deletions lib/csv_importer/row.rb
Original file line number Diff line number Diff line change
Expand Up @@ -52,18 +52,19 @@ def set_attributes(model)
# Set the attribute using the column_definition and the csv_value
def set_attribute(model, column, csv_value)
column_definition = column.definition
if column_definition.to && column_definition.to.is_a?(Proc)
to_proc = column_definition.to
transformer = column_definition.to
if transformer.respond_to?(:call)
arity = transformer.is_a?(Proc) ? transformer.arity : transformer.method(:call).arity

case to_proc.arity
case arity
when 1 # to: ->(email) { email.downcase }
model.public_send("#{column_definition.name}=", to_proc.call(csv_value))
model.public_send("#{column_definition.name}=", transformer.call(csv_value))
when 2 # to: ->(published, post) { post.published_at = Time.now if published == "true" }
to_proc.call(csv_value, model)
transformer.call(csv_value, model)
when 3 # to: ->(field_value, post, column) { post.hash_field[column.name] = field_value }
to_proc.call(csv_value, model, column)
transformer.call(csv_value, model, column)
else
raise ArgumentError, "`to` proc can only have 1, 2 or 3 arguments"
raise ArgumentError, "arity: #{transformer.arity.inspect} - `to` can only have 1, 2 or 3 arguments"
end
else
attribute = column_definition.attribute
Expand Down
12 changes: 8 additions & 4 deletions spec/csv_importer_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -61,14 +61,18 @@ def self.store
class ImportUserCSV
include CSVImporter

class ConfirmedProcessor
def self.call(confirmed, model)
model.confirmed_at = confirmed == "true" ? Time.new(2012) : nil
end
end

model User

column :email, required: true, as: /email/i, to: ->(email) { email.downcase }
column :f_name, as: :first_name, required: true
column :last_name, to: :l_name
column :confirmed, to: ->(confirmed, model) do
model.confirmed_at = confirmed == "true" ? Time.new(2012) : nil
end
column :confirmed, to: ConfirmedProcessor
column :extra, as: /extra/i, to: ->(value, model, column) do
model.custom_fields[column.name] = value
end
Expand Down Expand Up @@ -495,7 +499,7 @@ class ImportUserCSVByFirstName
import = ImportUserCSV.new(content: csv_content).run!

expect(import).to_not be_success
expect(import.message).to eq "Unclosed quoted field on line 3."
expect(import.message).to include "Unclosed quoted field"
end

it "matches columns via regexp" do
Expand Down

0 comments on commit 3c9d9b2

Please sign in to comment.