{"id":20081917,"url":"https://github.com/eval/total_recall","last_synced_at":"2025-08-02T07:09:31.007Z","repository":{"id":2190461,"uuid":"3138373","full_name":"eval/total_recall","owner":"eval","description":"Turn any csv into Ledger journals. Canonical repository can be found at --\u003e","archived":false,"fork":false,"pushed_at":"2017-03-09T00:11:00.000Z","size":48,"stargazers_count":17,"open_issues_count":0,"forks_count":1,"subscribers_count":3,"default_branch":"master","last_synced_at":"2025-07-14T22:49:22.737Z","etag":null,"topics":["csv","ledger","ruby"],"latest_commit_sha":null,"homepage":"https://gitlab.com/eval/total_recall","language":"Ruby","has_issues":false,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/eval.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2012-01-09T17:13:41.000Z","updated_at":"2024-12-27T22:40:07.000Z","dependencies_parsed_at":"2022-07-30T21:48:02.123Z","dependency_job_id":null,"html_url":"https://github.com/eval/total_recall","commit_stats":null,"previous_names":[],"tags_count":5,"template":false,"template_full_name":null,"purl":"pkg:github/eval/total_recall","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/eval%2Ftotal_recall","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/eval%2Ftotal_recall/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/eval%2Ftotal_recall/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/eval%2Ftotal_recall/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/eval","download_url":"https://codeload.github.com/eval/total_recall/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/eval%2Ftotal_recall/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":268347895,"owners_count":24236290,"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","status":"online","status_checked_at":"2025-08-02T02:00:12.353Z","response_time":74,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"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","ledger","ruby"],"created_at":"2024-11-13T15:40:55.160Z","updated_at":"2025-08-02T07:09:30.956Z","avatar_url":"https://github.com/eval.png","language":"Ruby","readme":"# TotalRecall [![build status](https://gitlab.com/eval/total_recall/badges/master/build.svg)](https://gitlab.com/eval/total_recall/commits/master)\n\nTurn **any** csv-file into a [Ledger](http://ledger-cli.org/) journal.\n\n## Introduction\n\n`total_recall` assumes nothing about the structure of your csv, nor of the ledger-file you want to create.  \nInstead, one creates a yaml-config consisting of:\n* a [mustache-template](https://github.com/defunkt/mustache) of the ledger-file\n* the source (and parse-options) of the csv\n* the value of every template-variable via Ruby lambdas\n\n## Example\n\nAfter installation you run `total_recall init bank` to generate the following file:\n```yaml\n# file: bank.yml\n:total_recall:\n  :version: 0.6.0\n:template:\n  :raw: |-\n    ; -*- ledger -*-¬\n\n    {{# transactions}}\n    {{date}} {{{description}}}\n      {{to}}    EUR {{amount}}\n      {{from}}\n\n    {{/ transactions}}\n\n:csv:\n  #:file: total_recall.csv\n  :raw: |-\n    \"2013-11-01\",\"Foo\",\"2013-11-02\",\"1.638,00\"\n    \"2013-11-02\",\"Bar\",\"2013-11-03\",\"-492,93\"\n  :options:\n    #:col_sep: \";\"\n    #:headers: false\n\n:context:\n  :transactions:\n    :__defaults__:\n      :from: !!proc |\n        ask_account(\"What account provides these transactions?\", default: 'Assets:Checking')\n    :date: !!proc row[0]\n    :description: !!proc row[1]\n    :amount: !!proc row[3]\n    :to: !!proc |\n      render_row(columns: [0, 1, 3])\n      ask_account(\"To what account did the money go?\")\n```\n\nThe `template`-section is pretty straightforward: you can add any variable you need using the [mustache-syntax](http://mustache.github.io/mustache.5.html).  \nThe `csv`-section defines where csv comes from and what parse-options should be used. It's best to start with a csv-snippet in `raw` (and leave `file` commented) in order to test-run the config.\n\nIn the `context`-section the actual mapping is done: in this section your should define a key for every variable in the template.  \nA key's value is derived from the csv via Ruby. This can be done via a simple mapping: `:date: !!proc row[0]`, via some specific operation: `:data: !!proc Date.parse(row[0]).iso8601` or via one of the [interactive helpers](https://gitlab.com/eval/total_recall/blob/v0.6.0/lib/total_recall.rb#L27-50) as you can see for the `to`-field above.  \nFields can also have default-values: the `from`-field for example is the same for all rows.\n\nAs it's all Ruby, you can make the mapping as smart as you like:\n```\n:context:\n  :transactions:\n    :description: !!proc row[3]\n    :to: !!proc |\n      guess = begin\n        case self.description # the description-field is defined above\n        when /CREDITCARD/ then \"Liabilities:MasterCard\"\n        when /INTERNET/i then \"Expenses:Communication\"\n        end\n      end\n      ask_account(\"To what account did the money go?\", default: guess)\n...\n```\n\nSee [Extensibility](#extensibility) below for providing your own Ruby module with helpers (i.e. your own self-learning account-guesser!).\n\nOnce your config is done, you can give it a spin:\n```bash\n# the result will be echoed:\n$ total_recall ledger -c bank.yml\n\n# to quickly see if the output is actually valid ledger:\n$ total_recall ledger -c bank.yml | ledger -f - reg\n```\n\nWhen the output looks good and doesn't make Ledger choke, you can uncomment the file-key in the csv-section and run it against the real csv-data:\n```bash\n$ total_recall ledger -c bank.yml \u003e bank.dat\n```\n\nThat's it!\n\nTo see an extensive annotated config-file do:\n```bash\n$ total_recall sample\n```\n\n## Install\n\n```bash\ngem install total_recall\n```\n\n## Usage\n\n```bash\ntotal_recall\n\n# Commands:\n#   total_recall help [COMMAND]              # Describe available commands or one specific command\n#   total_recall init NAME                   # Generate a minimal config NAME.yml\n#   total_recall ledger -c, --config=CONFIG  # Convert CONFIG to a ledger\n#   total_recall sample                      # Generate an annotated config\n#   total_recall version                     # Show total_recall version\n\n# typically you would do:\ntotal_recall init my-bank\n\n# fiddle with the settings in 'my-bank.yml' and test-run it:\ntotal_recal ledger -c my-bank.yml\n# to skip prompts just provide dummy-data:\nyes 'Dummy' | total_recal ledger -c my-bank.yml\n\n# export it to a journal:\ntotal_recall ledger -c my-bank.yml \u003e my-bank.dat\n\n# verify correctness with ledger:\nledger -f my-bank.dat bal\n```\n\n## Extensibility\n\nYou can extend the ledger subcommand by passing a file with additions to it:\n\n```\ntotal_recall ledger -c my-bank.yml -r ./my_extension.rb\n```\n\nThis makes it possible to add helpers or redefine existing ones:\n\n```ruby\ncat my_extension.rb\nmodule MyExtension\n  # adding some options to an existing helper:\n  def ask_account(question, options = {})\n    question.upcase! if options.delete(:scream)\n    super\n  end\n\n  # a new helper:\n  def guess_account(question, options = {})\n    guess = Guesser.new.guess\n    ask_account(question, default: guess)\n  end\nend\n\nTotalRecall::SessionHelper.include MyExtension\n```\n\n## Develop\n    \n```bash\ngit clone https://gitlab.com/eval/total_recall.git\ncd total_recall\nbundle\nbundle exec rake spec\n```\n## Author\n\nGert Goet (eval) :: gert@thinkcreate.nl :: @gertgoet\n\n## License\n\n(The MIT license)\n\nCopyright (c) 2017 Gert Goet, ThinkCreate\n\nPermission is hereby granted, free of charge, to any person obtaining\na copy of this software and associated documentation files (the\n\"Software\"), to deal in the Software without restriction, including\nwithout limitation the rights to use, copy, modify, merge, publish,\ndistribute, sublicense, and/or sell copies of the Software, and to\npermit persons to whom the Software is furnished to do so, subject to\nthe following conditions:\n\nThe above copyright notice and this permission notice shall be\nincluded in all copies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND,\nEXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\nMERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND\nNONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE\nLIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION\nOF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION\nWITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Feval%2Ftotal_recall","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Feval%2Ftotal_recall","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Feval%2Ftotal_recall/lists"}