{"id":13879606,"url":"https://github.com/pcriv/smuggle","last_synced_at":"2025-04-29T00:30:51.561Z","repository":{"id":52574689,"uuid":"101987498","full_name":"pcriv/smuggle","owner":"pcriv","description":"Manage exports and imports with ease, separating the logic from the models","archived":false,"fork":false,"pushed_at":"2023-09-24T06:56:43.000Z","size":94,"stargazers_count":28,"open_issues_count":2,"forks_count":0,"subscribers_count":6,"default_branch":"main","last_synced_at":"2025-04-22T05:57:08.263Z","etag":null,"topics":["csv-export","csv-import","ruby"],"latest_commit_sha":null,"homepage":"","language":"Ruby","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"other","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/pcriv.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":"CODE_OF_CONDUCT.md","threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null}},"created_at":"2017-08-31T10:04:23.000Z","updated_at":"2024-10-13T22:26:30.000Z","dependencies_parsed_at":"2023-07-22T05:46:58.019Z","dependency_job_id":"3d626ce4-fe80-447b-b430-180822b8f2f0","html_url":"https://github.com/pcriv/smuggle","commit_stats":null,"previous_names":["inspirenl/smuggle"],"tags_count":4,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/pcriv%2Fsmuggle","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/pcriv%2Fsmuggle/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/pcriv%2Fsmuggle/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/pcriv%2Fsmuggle/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/pcriv","download_url":"https://codeload.github.com/pcriv/smuggle/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":251410200,"owners_count":21584979,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["csv-export","csv-import","ruby"],"created_at":"2024-08-06T08:02:26.606Z","updated_at":"2025-04-29T00:30:51.242Z","avatar_url":"https://github.com/pcriv.png","language":"Ruby","readme":"# Smuggle\n\n[![Gem](https://img.shields.io/gem/v/smuggle.svg?style=flat)](http://rubygems.org/gems/smuggle)\n[![Depfu](https://badges.depfu.com/badges/6f2f73672eae4d603d6ae923164435e2/overview.svg)](https://depfu.com/github/pcriv/smuggle?project=Bundler)\n[![Inline docs](http://inch-ci.org/github/pcriv/smuggle.svg?branch=master\u0026style=shields)](http://inch-ci.org/github/pcriv/smuggle)\n[![Maintainability](https://api.codeclimate.com/v1/badges/b7192c49c395b2ac9bac/maintainability)](https://codeclimate.com/github/pcriv/smuggle/maintainability)\n[![Test Coverage](https://api.codeclimate.com/v1/badges/b7192c49c395b2ac9bac/test_coverage)](https://codeclimate.com/github/pcriv/smuggle/test_coverage)\n\nIs 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.\n\n**Smuggle is not dependent on Rails**, you can use it on ActiveModel/ActiveRecord models, as well as plain ruby objects and hashes.\n\nLinks:\n\n- [API Docs](https://www.rubydoc.info/gems/smuggle)\n- [Contributing](https://github.com/pcriv/smuggle/blob/master/CONTRIBUTING.md)\n- [Code of Conduct](https://github.com/pcriv/smuggle/blob/master/CODE_OF_CONDUCT.md)\n\n## Requirements\n\n1. [Ruby 3.0.0](https://www.ruby-lang.org)\n\n## Installation\n\nTo install, run:\n\n```sh\ngem install smuggle\n```\n\nOr add the following to your Gemfile:\n\n```sh\ngem \"smuggle\"\n```\n\n## Usage\n\n### Exporters\n\nGiven the following plain old ruby object:\n\n```ruby\nclass User\n  attr_accessor :name\n\n  def initialize(name)\n    @name = name\n  end\nend\n```\n\nAn exporter can be defined by inheriting from [Smuggle::Exporter::Base](lib/smuggle/exporter/base.rb) and defining the attributes to export:\n\n```ruby\nclass UserExporter \u003c Smuggle::Exporter::Base\n  attributes :name\nend\n```\n\nExtra logic can be establish inside the exporter file, using the same name as the attribute:\n\n```ruby\nclass UserExporter \u003c Smuggle::Exporter::Base\n  attributes :name\n\n  def name\n    super + \" - exported\"\n  end\nend\n```\n\nIf there are no attributes defined in the exporter and you are using ActiveModel or ActiveRecord, all the attributes of the record will be included.\nIf it is a hash, then all values will be included.\n\nTo generate the csv data simply call:\n\n```ruby\nusers = [User.new(\"Rick Sanchez\"), User.new(\"Morty Smith\")]\nSmuggle::Services::Export.call(scope: users, exporter: UserExporter)\n# =\u003e \"Full name,Full name\\nRick Sanchez,Rick Sanchez\\nMorty Smith,Morty Smith\\n\"\n```\n\nOr if you are using ActiveRecord, the exporter class will be automatically resolved from the scope:\n\n```ruby\nSmuggle::Services::Export.call(scope: User.all)\n```\n\nTo add labels for your attributes (to show in the header instead of the raw attribute keys) you can add **attribute_labels** to your exporter:\n\n``` ruby\nclass UserExporter \u003c Smuggle::Exporter::Base\n  attributes :name\n  attribute_labels name: \"Full name\"\nend\n\nusers = [User.new(\"Rick Sanchez\"), User.new(\"Morty Smith\")]\n\nSmuggle::Services::Export.call(scope: users, exporter: UserExporter)\n# =\u003e \"Full name\\nRick Sanchez\\nMorty Smith\\n\"\n```\n\n### Importers\n\nGiven the following plain old ruby object:\n\n```ruby\nclass User\n  attr_accessor :name\n\n  def initialize(name)\n    @name = name\n  end\nend\n```\n\nAn importer can be defined by inheriting from [Smuggle::Importer::Base](lib/smuggle/importer/base.rb) and defining the attributes to export:\n\n```ruby\nclass UserImporter \u003c Smuggle::Importer::Base\n  # If no attributes are defined, the importer will infer them from the model's .attribute_names\n  # If any attributes are explicitly defined, all other entries in the CSV are ignored\n  attributes :name\n\n  # Computed attributes from the row data\n  def name\n    [row[:first_name], row[:last_name]].join(\" \")\n  end\n\n  def persist\n    # Create your instance here\n    model.new(to_h)\n    # The result is collected by the Import service\n\n    # If you want to persist your data, you can do so here. This is an example using ActiveRecord\n    # model.create(to_h)\n  end\nend\n```\n\nFor example:\n\nGiven the following `users.csv` file:\n\n```\n\"first_name\",\"last_name\"\n\"Rick\",\"Sanchez\"\n\"Morty\",\"Smith\"\n```\n\nJust run:\n\n```ruby\nSmuggle::Services::Import.call(model: User, filepath: \"users.csv\")\n# =\u003e [#\u003cUser name: \"Rick Sanchez\"\u003e, #\u003cUser name: \"Morty Smith\"\u003e]\n```\n\nThe importer class will be resolved from the model name, otherwise you could explicitely set the importer like this:\n\n```ruby\nSmuggle::Services::Import.call(model: User, filepath: \"users.csv\", importer: UserImporter)\n```\n\n### Generators\n\nIf you are using rails you can use the following generators:\n\n```\n$ rails g smuggle:install\ncreate app/exporters/application_exporter.rb\ncreate app/importers/application_importer.rb\n```\n\nTo generate an exporter, you can run the following command:\n\n```\n$ rails g smuggle:exporter user\ncreate app/exporters/user_exporter.rb\n```\n\nYou can also include the attributes you wish to export by running:\n\n```\n$ rails g smuggle:exporter user email username created_at\ncreate app/exporters/user_exporter.rb\n```\n\nAnd to generate an importer, just run:\n\n```\n$ rails g smuggle:importer user email username full_name\ncreate app/importers/user_importer.rb\n```\n\n## Tests\n\nTo test, run:\n\n```\nbundle exec rspec spec/\n```\n\n## Versioning\n\nRead [Semantic Versioning](https://semver.org) for details. Briefly, it means:\n\n- Major (X.y.z) - Incremented for any backwards incompatible public API changes.\n- Minor (x.Y.z) - Incremented for new, backwards compatible, public API enhancements/fixes.\n- Patch (x.y.Z) - Incremented for small, backwards compatible, bug fixes.\n\n## License\n\nOriginal work copyright 2017-2019 [Inspire Innovation BV](https://inspire.nl).\nContinued work copyright 2019 [Pablo Crivella](https://pcriv.com).\n\nRead [LICENSE](LICENSE) for details.\n\nThe development of this gem has been sponsored by Inspire Innovation BV (Utrecht, The Netherlands).\n","funding_links":[],"categories":["Ruby"],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fpcriv%2Fsmuggle","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fpcriv%2Fsmuggle","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fpcriv%2Fsmuggle/lists"}