Skip to content
Manage exports and imports with ease, separating the logic from the models
Ruby Shell
Branch: master
Clone or download
Permalink
Type Name Latest commit message Commit time
Failed to load latest commit information.
.circleci Update dependencies and remove deprecations Apr 24, 2019
bin
lib Bump version and update CHANGELOG Jul 16, 2019
spec
.editorconfig Update editorconfig file Sep 9, 2018
.gitignore
.rspec Generate new gem Aug 31, 2017
.rubocop.yml Update dependencies and remove deprecations Apr 24, 2019
.ruby-version Add ruby version Apr 24, 2019
.yardopts Update CHANGELOG Sep 10, 2018
CHANGELOG.md
CODE_OF_CONDUCT.md Generate new gem Aug 31, 2017
CONTRIBUTING.md Add contribution guidelines Sep 9, 2018
Gemfile Fix rubocop offenses Sep 9, 2018
LICENSE Update README.md to reflect Inspire sponsorship Aug 14, 2019
README.md Update README.md to reflect Inspire sponsorship Aug 14, 2019
Rakefile Run formatter Jul 21, 2019
smuggle.gemspec Update faker to version 2.1.0 Aug 7, 2019

README.md

Smuggle

Gem Depfu Inline docs CircleCI Maintainability Test Coverage

Is a gem to manage exports and imports with ease, separating the logic from the models, resulting in a much cleaner codebase. Easy to use, with familiar structure.

Smuggle is not dependent on Rails, you can use it on ActiveModel/ActiveRecord models, as well as plain ruby objects and hashes.

Links:

Requirements

  1. Ruby 2.5.0

Installation

To install, run:

gem install smuggle

Or add the following to your Gemfile:

gem "smuggle"

Usage

Exporters

Given the following plain old ruby object:

class User
  attr_accessor :name

  def initialize(name)
    @name = name
  end
end

An exporter can be defined by inheriting from Smuggle::Exporter::Base and defining the attributes to export:

class UserExporter < Smuggle::Exporter::Base
  attributes :name
end

Extra logic can be establish inside the exporter file, using the same name as the attribute:

class UserExporter < Smuggle::Exporter::Base
  attributes :name

  def name
    super + " - exported"
  end
end

If there are no attributes defined in the exporter and you are using ActiveModel or ActiveRecord, all the attributes of the record will be included. If it is a hash, then all values will be included.

To generate the csv data simply call:

users = [User.new("Rick Sanchez"), User.new("Morty Smith")]
Smuggle::Services::Export.call(scope: users, exporter: UserExporter)
# => "Full name,Full name\nRick Sanchez,Rick Sanchez\nMorty Smith,Morty Smith\n"

Or if you are using ActiveRecord, the exporter class will be automatically resolved from the scope:

Smuggle::Services::Export.call(scope: User.all)

To add labels for your attributes (to show in the header instead of the raw attribute keys) you can add attribute_labels to your exporter:

class UserExporter < Smuggle::Exporter::Base
  attributes :name
  attribute_labels name: "Full name"
end

users = [User.new("Rick Sanchez"), User.new("Morty Smith")]

Smuggle::Services::Export.call(scope: users, exporter: UserExporter)
# => "Full name\nRick Sanchez\nMorty Smith\n"

Importers

Given the following plain old ruby object:

class User
  attr_accessor :name

  def initialize(name)
    @name = name
  end
end

An importer can be defined by inheriting from Smuggle::Importer::Base and defining the attributes to export:

class UserImporter < Smuggle::Importer::Base
  # If no attributes are defined, the importer will infer them from the model's .attribute_names
  # If any attributes are explicitly defined, all other entries in the CSV are ignored
  attributes :name

  # Computed attributes from the row data
  def name
    [row[:first_name], row[:last_name]].join(" ")
  end

  def persist
    # Create your instance here
    model.new(to_h)
    # The result is collected by the Import service

    # If you want to persist your data, you can do so here. This is an example using ActiveRecord
    # model.create(to_h)
  end
end

For example:

Given the following users.csv file:

"first_name","last_name"
"Rick","Sanchez"
"Morty","Smith"

Just run:

Smuggle::Services::Import.call(model: User, filepath: "users.csv")
# => [#<User name: "Rick Sanchez">, #<User name: "Morty Smith">]

The importer class will be resolved from the model name, otherwise you could explicitely set the importer like this:

Smuggle::Services::Import.call(model: User, filepath: "users.csv", importer: UserImporter)

Generators

If you are using rails you can use the following generators:

$ rails g smuggle:install
create app/exporters/application_exporter.rb
create app/importers/application_importer.rb

To generate an exporter, you can run the following command:

$ rails g smuggle:exporter user
create app/exporters/user_exporter.rb

You can also include the attributes you wish to export by running:

$ rails g smuggle:exporter user email username created_at
create app/exporters/user_exporter.rb

And to generate an importer, just run:

$ rails g smuggle:importer user email username full_name
create app/importers/user_importer.rb

Tests

To test, run:

bundle exec rspec spec/

Versioning

Read Semantic Versioning for details. Briefly, it means:

  • Major (X.y.z) - Incremented for any backwards incompatible public API changes.
  • Minor (x.Y.z) - Incremented for new, backwards compatible, public API enhancements/fixes.
  • Patch (x.y.Z) - Incremented for small, backwards compatible, bug fixes.

License

Original work copyright 2017-2019 Inspire Innovation BV. Continued work copyright 2019 Pablo Crivella.

Read LICENSE for details.

The development of this gem has been sponsored by Inspire Innovation BV (Utrecht, The Netherlands).

You can’t perform that action at this time.