{"id":13878116,"url":"https://github.com/lassoid/tiny_filter","last_synced_at":"2025-10-31T15:30:29.233Z","repository":{"id":64632176,"uuid":"574140723","full_name":"lassoid/tiny_filter","owner":"lassoid","description":"Simple filtering for ActiveRecord, Sequel and enumerables.","archived":false,"fork":false,"pushed_at":"2024-05-19T00:28:48.000Z","size":70,"stargazers_count":22,"open_issues_count":0,"forks_count":1,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-01-29T09:22:23.083Z","etag":null,"topics":["filter","filtering","gem","rails","ruby","ruby-on-rails"],"latest_commit_sha":null,"homepage":"","language":"Ruby","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/lassoid.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"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,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2022-12-04T14:56:05.000Z","updated_at":"2024-09-12T06:06:51.000Z","dependencies_parsed_at":"2023-01-31T10:00:59.318Z","dependency_job_id":"6e788649-84a4-4e04-90ac-4a6cf6229b07","html_url":"https://github.com/lassoid/tiny_filter","commit_stats":{"total_commits":23,"total_committers":3,"mean_commits":7.666666666666667,"dds":"0.34782608695652173","last_synced_commit":"a2f80091fc0a920c62c473948f17ea03db8734a7"},"previous_names":[],"tags_count":6,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/lassoid%2Ftiny_filter","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/lassoid%2Ftiny_filter/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/lassoid%2Ftiny_filter/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/lassoid%2Ftiny_filter/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/lassoid","download_url":"https://codeload.github.com/lassoid/tiny_filter/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":238828888,"owners_count":19537709,"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":["filter","filtering","gem","rails","ruby","ruby-on-rails"],"created_at":"2024-08-06T08:01:40.282Z","updated_at":"2025-10-31T15:30:29.185Z","avatar_url":"https://github.com/lassoid.png","language":"Ruby","readme":"# TinyFilter\n\n[![Gem Version](https://img.shields.io/gem/v/tiny_filter?color=blue\u0026label=version)](https://rubygems.org/gems/tiny_filter)\n[![Gem downloads count](https://img.shields.io/gem/dt/tiny_filter)](https://rubygems.org/gems/tiny_filter)\n[![Github Actions CI](https://github.com/lassoid/tiny_filter/actions/workflows/main.yml/badge.svg?branch=main)](https://github.com/lassoid/tiny_filter/actions/workflows/main.yml)\n\nTinyFilter is created to provide a simple object-oriented abstraction layer for filtering collections.\nIt is mainly purposed for ActiveRecord/Sequel models, but you can also use it with any enumerable.\n\n```ruby\nPost.where(title: \"Wow!\").filter_by(from: 2.days.ago, to: 1.day.ago).order(:created_at)\n```\n\n## Installation\n\n1. Install the gem and add to the application's Gemfile by executing:\n\n   ```shell\n   bundle add tiny_filter\n   ```\n\n2. Generate an application filter as an entry point to all your future filters:\n\n   ```shell\n   bin/rails g tiny_filter:install\n   ```\n\nThis will generate `ApplicationFilter` inside `app/filters` directory.\nThis directory is intended to store all your filters.\n\n## Adding a filter\n\nTo generate a filter class simply run `tiny_filter:filter` command.\n\nFor example, to create a filter class for `Post` with filters `from` and `to`, run:\n\n```shell\nbin/rails g tiny_filter:filter post from to\n```\n\nThis will generate the `PostFilter` class inside the `app/filters` directory with `from` and `to` filters.\n\nEach filter is defined by calling `filters` method inside class body.\n\n`filters` accepts two arguments:\n- `key` - a filter name, used as identifier;\n- `block` - a block with filter logic, that returns filtered collection and itself accepts two arguments:\n  - `scope` - a collection that should be filtered;\n  - `value` - a value for filtering.\n\nWhen you perform filtering, provided key indicate filter `key` and provided value is passed to `value` param in corresponding filter `block`.\n`scope`s receive collections in a pipeline manner:\n_first_ executed filter receives _original collection_,\n_second and further_ receive the _return collection_ of the previous filter.\n\nTo execute filtering, simply call `filter` with the initial scope and options provided.\n\n```ruby\nclass UserFilter \u003c ApplicationFilter\n  filters(:name) { |scope, value| scope.where(first_name: value) }\n  filters(:surname) { |scope, value| scope.where(last_name: value) }\nend\n\nUserFilter.filter(User, name: \"John\", surname: \"Doe\")\n# Which is equivalent to:\n# User.where(first_name: \"John\").where(last_name: \"Doe\")\n```\n\nNotice, that your filters _must_ return the same scope type as they accept.\nIt guarantees that scope behaves the same way as in other filters in this class.\n\n```ruby\nfilters(:title) { |scope, value| scope.where(\"title ILIKE ?\", value) }\n\n# bad - scope is an ActiveRecord collection, but the return value is an array.\nfilters(:from) { |scope, value| scope.select { |e| e.created_at \u003e= value } }\n\n# good - scope and return value are both ActiveRecord collections.\nfilters(:from) { |scope, value| scope.where(\"created_at \u003e= ?\", value) }\n```\n\nThus if the initial scope for filtering is an ActiveRecord collection,\nit is a bad practice for filter to return not an ActiveRecord collection.\nOtherwise you can face errors depending on the provided options order.\n\n## ORM integration\n\n### ActiveRecord\n\nTinyFilter provides a simple concern, that adds just one method `filter_by`,\nthat can be used in ActiveRecord method chaining.\n\nJust include `TinyFilter::Concern` in your model and that's all!\n\n```ruby\nclass Post \u003c ApplicationRecord\n  include TinyFilter::Concern\nend\n```\n\nNow you can use filtering everywhere in your model method chaining.\n\n```ruby\nPost.where(title: \"something interesting\").filter_by(from: 2.days.ago, to: 1.day.ago).order(:title)\nPost.filter_by(from: 1.year.ago)\n```\n\n### Sequel\n\nThe previously mentioned filter concern can also be used in Sequel models.\n\n```ruby\nclass Artist \u003c Sequel::Model\n  include TinyFilter::Concern\nend\n```\n\nQuerying examples:\n\n```ruby\nArtist.where(name: \"Kirill\").filter_by(from: 2.days.ago, to: 1.day.ago).order(:name).all\nArtist.filter_by(from: 1.year.ago).all\n```\n\n### Naming convention\n\nBy default a filter class and a model are mapped by a _model name_ with a _suffix_ `Filter`.\nFor example, the model `My::Class` by default will use the `My::ClassFilter` as a filter class.\n\nYou can customize this behavior by implementing a `filter_class` class method\nwith an appropriate class as a return value.\n\n```ruby\nclass My::Class \u003c ApplicationRecord\n   # ...\n   def self.filter_class\n      CustomFilter\n   end\n   # ...\nend\n```\n\n## Using with Plain objects\n\nYou can use filters with Plain Old Ruby collections like so:\n\n```ruby\noptions    # filter options, for example: `{ from: 2.days.ago, to: 1.day.ago }`\ncollection # can be any Enumerable: array, hash, your custom collection, etc etc\n\nMyFilter.filter(collection, options)\n```\n\n## Development\n\nAfter checking out the repo, run `bin/setup` to install dependencies. Then, run `bin/rspec` to run the tests.\nYou can also run `bin/rubocop` to lint the source code\nand `bin/console` for an interactive prompt that will allow you to experiment.\n\nTo install this gem onto your local machine, run `bin/rake install`.\nTo release a new version, update the version number in `version.rb`, and then run `bin/rake release`,\nwhich will create a git tag for the version, push git commits and the created tag,\nand push the `.gem` file to [rubygems.org](https://rubygems.org).\n\n## Contributing\n\nBug reports and pull requests are welcome on GitHub at https://github.com/lassoid/tiny_filter.\nThis project is intended to be a safe, welcoming space for collaboration, and contributors\nare expected to adhere to the [code of conduct](https://github.com/lassoid/tiny_filter/blob/main/CODE_OF_CONDUCT.md).\n\n## License\n\nThe gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).\n\n## Code of Conduct\n\nEveryone interacting in the TinyFilter project's codebases, issue trackers, chat rooms and mailing lists\nis expected to follow the [code of conduct](https://github.com/lassoid/tiny_filter/blob/main/CODE_OF_CONDUCT.md).\n","funding_links":[],"categories":["Ruby"],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Flassoid%2Ftiny_filter","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Flassoid%2Ftiny_filter","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Flassoid%2Ftiny_filter/lists"}