{"id":13879730,"url":"https://github.com/jetrockets/metka","last_synced_at":"2025-08-16T12:31:47.590Z","repository":{"id":43026151,"uuid":"203344834","full_name":"jetrockets/metka","owner":"jetrockets","description":"Rails gem to manage tags with PostgreSQL array columns.","archived":false,"fork":false,"pushed_at":"2023-03-08T20:51:20.000Z","size":158,"stargazers_count":52,"open_issues_count":8,"forks_count":3,"subscribers_count":7,"default_branch":"master","last_synced_at":"2024-11-24T08:32:58.108Z","etag":null,"topics":["orm-extension","rails-gem","rails-tagging","social","tagging"],"latest_commit_sha":null,"homepage":null,"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/jetrockets.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE.txt","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":"2019-08-20T09:33:39.000Z","updated_at":"2024-08-31T19:42:24.000Z","dependencies_parsed_at":"2024-01-03T02:24:32.717Z","dependency_job_id":"6eb25ee2-03e2-4ae3-a545-6aa5acb0b519","html_url":"https://github.com/jetrockets/metka","commit_stats":{"total_commits":92,"total_committers":10,"mean_commits":9.2,"dds":"0.44565217391304346","last_synced_commit":"be474c917d9c1604d0e66ac42a630e64224278a2"},"previous_names":[],"tags_count":15,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jetrockets%2Fmetka","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jetrockets%2Fmetka/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jetrockets%2Fmetka/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jetrockets%2Fmetka/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/jetrockets","download_url":"https://codeload.github.com/jetrockets/metka/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":230037776,"owners_count":18163188,"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":["orm-extension","rails-gem","rails-tagging","social","tagging"],"created_at":"2024-08-06T08:02:30.624Z","updated_at":"2024-12-16T22:48:15.143Z","avatar_url":"https://github.com/jetrockets.png","language":"Ruby","funding_links":[],"categories":["Ruby","Gems"],"sub_categories":["Articles"],"readme":"[![Gem Version](https://badge.fury.io/rb/metka.svg)](https://badge.fury.io/rb/metka)\n[![Build Status](https://github.com/jetrockets/metka/workflows/Specs/badge.svg?branch=master)](https://github.com/jetrockets/metka/actions)\n[![Open Source Helpers](https://www.codetriage.com/jetrockets/metka/badges/users.svg)](https://www.codetriage.com/jetrockets/metka)\n\n# Metka\n\nRails gem to manage tags with PostgreSQL array columns.\n\n:exclamation: Requirements:\n\n* Ruby ~\u003e 2.5\n* Rails \u003e= 5.2 (for Rails 5.1 and 5.0 use version \u003c2.1.0)\n\n## Installation\n\nAdd this line to your application's Gemfile:\n\n```ruby\ngem 'metka'\n```\n\nAnd then execute:\n\n```bash\nbundle\n```\n\nOr install it yourself as:\n\n```bash\ngem install metka\n```\n\n## Tag objects\n\n```bash\nrails g migration CreateSongs\n```\n\n```ruby\nclass CreateSongs \u003c ActiveRecord::Migration[5.0]\n  def change\n    create_table :songs do |t|\n      t.string :title\n      t.string :tags, array: true, default: [], index: { using: :gin }\n      t.string :genres, array: true, default: [], index: { using: :gin }\n      t.timestamps\n    end\n  end\nend\n```\n\n```ruby\nclass Song \u003c ActiveRecord::Base\n  include Metka::Model(columns: %w[genres tags])\nend\n\n@song = Song.new(title: 'Migrate tags in Rails to PostgreSQL')\n@song.tag_list = 'top, chill'\n@song.genre_list = 'rock, jazz, pop'\n@song.save\n```\n\n## Find tagged objects\n\n### .with_all_#{column_name}\n\n```ruby\nSong.with_all_tags('top')\n#=\u003e [#\u003cSong id: 1, title: 'Migrate tags in Rails to PostgreSQL', tags: ['top', 'chill'], genres: ['rock', 'jazz', 'pop']]\n\nSong.with_all_tags('top, 1990')\n#=\u003e []\n\nSong.with_all_tags('')\n#=\u003e [#\u003cSong id: 1, title: 'Migrate tags in Rails to PostgreSQL', tags: ['top', 'chill'], genres: ['rock', 'jazz', 'pop']]\n\nSong.with_all_tags(nil)\n#=\u003e [#\u003cSong id: 1, title: 'Migrate tags in Rails to PostgreSQL', tags: ['top', 'chill'], genres: ['rock', 'jazz', 'pop']]\n\nSong.with_all_genres('rock')\n#=\u003e [#\u003cSong id: 1, title: 'Migrate tags in Rails to PostgreSQL', tags: ['top', 'chill'], genres: ['rock', 'jazz', 'pop']]\n```\n\n### .with_any_#{column_name}\n\n```ruby\nSong.with_any_tags('chill')\n#=\u003e [#\u003cSong id: 1, title: 'Migrate tags in Rails to PostgreSQL', tags: ['top', 'chill'], genres: ['rock', 'jazz', 'pop']]\n\nSong.with_any_tags('chill, 1980')\n#=\u003e [#\u003cSong id: 1, title: 'Migrate tags in Rails to PostgreSQL', tags: ['top', 'chill'], genres: ['rock', 'jazz', 'pop']]\n\nSong.with_any_tags('')\n#=\u003e [#\u003cSong id: 1, title: 'Migrate tags in Rails to PostgreSQL', tags: ['top', 'chill'], genres: ['rock', 'jazz', 'pop']]\n\nSong.with_any_tags(nil)\n#=\u003e [#\u003cSong id: 1, title: 'Migrate tags in Rails to PostgreSQL', tags: ['top', 'chill'], genres: ['rock', 'jazz', 'pop']]\n\nSong.with_any_genres('rock, rap')\n#=\u003e [#\u003cSong id: 1, title: 'Migrate tags in Rails to PostgreSQL', tags: ['top', 'chill'], genres: ['rock', 'jazz', 'pop']]\n```\n\n### .without_all_#{column_name}\n\n```ruby\nSong.without_all_tags('top')\n#=\u003e []\n\nSong.without_all_tags('top, 1990')\n#=\u003e [#\u003cSong id: 1, title: 'Migrate tags in Rails to PostgreSQL', tags: ['top', 'chill'], genres: ['rock', 'jazz', 'pop']]\n\nSong.without_all_tags('')\n#=\u003e [#\u003cSong id: 1, title: 'Migrate tags in Rails to PostgreSQL', tags: ['top', 'chill'], genres: ['rock', 'jazz', 'pop']]\n\nSong.without_all_tags(nil)\n#=\u003e [#\u003cSong id: 1, title: 'Migrate tags in Rails to PostgreSQL', tags: ['top', 'chill'], genres: ['rock', 'jazz', 'pop']]\n\nSong.without_all_genres('rock, pop')\n#=\u003e [#\u003cSong id: 1, title: 'Migrate tags in Rails to PostgreSQL', tags: ['top', 'chill'], genres: ['rock', 'jazz', 'pop']]\n\nSong.without_all_genres('rock')\n#=\u003e []\n```\n\n### .without_any_#{column_name}\n\n```ruby\nSong.without_any_tags('top, 1990')\n#=\u003e []\n\nSong.without_any_tags('1990, 1980')\n#=\u003e [#\u003cSong id: 1, title: 'Migrate tags in Rails to PostgreSQL', tags: ['top', 'chill'], genres: ['rock', 'jazz', 'pop']]\n\nSong.without_any_genres('rock, pop')\n#=\u003e []\n\nSong.without_any_genres('')\n#=\u003e [#\u003cSong id: 1, title: 'Migrate tags in Rails to PostgreSQL', tags: ['top', 'chill'], genres: ['rock', 'jazz', 'pop']]\n\nSong.without_any_genres(nil)\n#=\u003e [#\u003cSong id: 1, title: 'Migrate tags in Rails to PostgreSQL', tags: ['top', 'chill'], genres: ['rock', 'jazz', 'pop']]\n```\n\n### .tagged_with\n\n```ruby\nSong.tagged_with('top')\n#=\u003e [#\u003cSong id: 1, title: 'Migrate tags in Rails to PostgreSQL', tags: ['top', 'chill'], genres: ['rock', 'jazz', 'pop']]\n\nSong.tagged_with('top, 1990')\n#=\u003e []\n\nSong.tagged_with('')\n#=\u003e [#\u003cSong id: 1, title: 'Migrate tags in Rails to PostgreSQL', tags: ['top', 'chill'], genres: ['rock', 'jazz', 'pop']]\n\nSong.tagged_with(nil)\n#=\u003e [#\u003cSong id: 1, title: 'Migrate tags in Rails to PostgreSQL', tags: ['top', 'chill'], genres: ['rock', 'jazz', 'pop']]\n\nSong.tagged_with('rock')\n#=\u003e [#\u003cSong id: 1, title: 'Migrate tags in Rails to PostgreSQL', tags: ['top', 'chill'], genres: ['rock', 'jazz', 'pop']]\n\nSong.tagged_with('rock', join_operator: Metka::And)\n#=\u003e []\n\nSong.tagged_with('chill', any: true)\n#=\u003e [#\u003cSong id: 1, title: 'Migrate tags in Rails to PostgreSQL', tags: ['top', 'chill'], genres: ['rock', 'jazz', 'pop']]\n\nSong.tagged_with('chill, 1980', any: true)\n#=\u003e [#\u003cSong id: 1, title: 'Migrate tags in Rails to PostgreSQL', tags: ['top', 'chill'], genres: ['rock', 'jazz', 'pop']]\n\nSong.tagged_with('', any: true)\n#=\u003e [#\u003cSong id: 1, title: 'Migrate tags in Rails to PostgreSQL', tags: ['top', 'chill'], genres: ['rock', 'jazz', 'pop']]\n\nSong.tagged_with('rock, rap', any: true, on: ['genres'])\n#=\u003e [#\u003cSong id: 1, title: 'Migrate tags in Rails to PostgreSQL', tags: ['top', 'chill'], genres: ['rock', 'jazz', 'pop']]\n\nSong.without_all_tags('top')\n#=\u003e []\n\nSong.tagged_with('top, 1990', exclude: true)\n#=\u003e [#\u003cSong id: 1, title: 'Migrate tags in Rails to PostgreSQL', tags: ['top', 'chill'], genres: ['rock', 'jazz', 'pop']]\n\nSong.tagged_with('', exclude: true)\n#=\u003e [#\u003cSong id: 1, title: 'Migrate tags in Rails to PostgreSQL', tags: ['top', 'chill'], genres: ['rock', 'jazz', 'pop']]\n\nSong.tagged_with('top, 1990', any: true, exclude: true)\n#=\u003e []\n\nSong.tagged_with('1990, 1980', any: true, exclude: true)\n#=\u003e [#\u003cSong id: 1, title: 'Migrate tags in Rails to PostgreSQL', tags: ['top', 'chill'], genres: ['rock', 'jazz', 'pop']]\n\nSong.without_any_genres('rock, pop')\n#=\u003e []\n```\n\n## Custom delimiter\n\nBy default, a comma is used as a delimiter to create tags from a string.\nYou can make your own custom separator:\n\n```ruby\nMetka.config.delimiter = '|'\nparsed_data = Metka::GenericParser.instance.call('cool, data|I have')\nparsed_data.to_a\n#=\u003e['cool, data', 'I have']\n```\n\n## Tags with quote\n\n```ruby\nparsed_data = Metka::GenericParser.instance.call(\"'cool, data', code\")\nparsed_data.to_a\n#=\u003e ['cool, data', 'code']\n```\n\n## Custom parser\n\nBy default we use [generic_parser](lib/metka/generic_parser.rb \"generic_parser\")\nIf you want to use your custom parser you can do:\n\n```ruby\nclass Song \u003c ActiveRecord::Base\n  include Metka::Model(columns: %w[genres tags], parser: Your::Custom::Parser.instance)\nend\n```\n\nCustom parser must be a singleton class that has a `.call` method that accepts the tag string\n\n## Tag Cloud Strategies\n\nThere are several strategies to get tag statistics\n\n### ActiveRecord Strategy (Default)\n\nData about taggings is accessible via class methods of your model with `Metka::Model` attached. You can calculate a cloud for a single tagged column or multiple columns, the latter case would return to you a sum of taggings from multiple tagged columns, that are provided as arguments, for each tag present. ActiveRecord Strategy is an easiest way to implement, since it wouldn't require any additional code, but it's the slowest one on SELECT.\n\n```ruby\n\nclass Book \u003c ActiveRecord::Base\n  include Metka::Model(column: 'authors')\n  include Metka::Model(column: 'co_authors')\nend\n\ntag_cloud = Book.author_cloud\n#=\u003e [[\"L.N. Tolstoy\", 3], [\"F.M. Dostoevsky\", 6]]\ngenre_cloud = Book.co_author_cloud\n#=\u003e [[\"A.P. Chekhov\", 5], [\"N.V. Gogol\", 8], [\"L.N. Tolstoy\", 2]]\nsummary_cloud = Book.metka_cloud('authors', 'co_authors')\n#=\u003e [[\"L.N. Tolstoy\", 5], [\"F.M. Dostoevsky\", 6], [\"A.P. Chekhov\", 5], [\"N.V. Gogol\", 8]]\n```\n\n### View Strategy\n\nData about taggings will be aggregated in SQL View. Performance-wise that strategy has no benefits over ActiveRecord Strategy, but if you need to store tags aggregations in a distinct model, that's an easiest way to achieve it.\n\n```bash\nrails g metka:strategies:view --source-table-name=NAME_OF_TABLE_WITH_TAGS [--source-columns=NAME_OF_COLUMN_1 NAME_OF_COLUMN_2] [--view-name=NAME_OF_RESULTING_VIEW]\n```\n\nThe code above will generate a migration that creates view with specified `NAME_OF_RESULTING_VIEW`, that would aggregate tags data from specified array of tagged columns [`NAME_OF_COLUMN_1`, `NAME_OF_COLUMN_2`, ...], that are present within specified table `NAME_OF_TABLE_WITH_TAGS`.\nIf `source-columns` option is not provided, then `tags` column would be used as defaults. If array of multiple values would be provided to the option, then the aggregation would be made with the tags from multiple tagged columns, so if a single tag would be found within multiple tagged columns, the resulting aggregation inside the view would have a single row for that tag with a sum of it's occurrences across all stated tagged columns.\n`view-name` option is also optional, it would just force the resulting view's name to the one of your choice. If it's not provided, then view name would be generated automatically, you could check it within generated migration.\n\nLets take a look at real example. We have a `notes` table with `tags` column.\n\n| Column | Type                | Default                           |\n|--------|---------------------|-----------------------------------|\n| id     | integer             | nextval('notes_id_seq'::regclass) |\n| body   | text                |                                   |\n| tags   | character varying[] | '{}'::character varying[]         |\n\nNow lets generate a migration.\n\n```bash\nrails g metka:strategies:view --source-table-name=notes\n```\n\nThe result would be:\n\n```ruby\n# frozen_string_literal: true\n\nclass CreateTaggedNotesView \u003c ActiveRecord::Migration[5.0]\n  def up\n    execute \u003c\u003c-SQL\n      CREATE OR REPLACE VIEW tagged_notes AS\n        SELECT\n          tag_name,\n          COUNT ( * ) AS taggings_count\n        FROM (\n          SELECT UNNEST\n            ( tags ) AS tag_name\n          FROM\n            view_posts\n        ) subquery\n        GROUP BY\n          tag_name;\n    SQL\n  end\n\n  def down\n    execute \u003c\u003c-SQL\n      DROP VIEW tagged_notes;\n    SQL\n  end\nend\n```\n\nNow lets take a look at `tagged_notes` view.\n\n| tag_name | taggings_count |\n|----------|----------------|\n| Ruby     | 124056         |\n| React    | 30632          |\n| Rails    | 28696          |\n| Crystal  | 6566           |\n| Elixir   | 3475           |\n\nNow you can create `TaggedNote` model and work with the view like you usually do with Rails models.\n\n### Materialized View Strategy\n\nData about taggings will be aggregated in SQL Materialized View, that would be refreshed with the trigger on each change of the tagged column's data. Except for the another type of view being used, that strategy behaves the same way, as a View Strategy above.\n\n```bash\nrails g metka:strategies:materialized_view --source-table-name=NAME_OF_TABLE_WITH_TAGS --source-columns=NAME_OF_COLUMN_1 NAME_OF_COLUMN_2 --view-name=NAME_OF_RESULTING_VIEW\n```\n\nAll of the options for that strategy's generation command are the same as for the View Strategy.\n\nThe migration template can be seen [here](spec/dummy/db/migrate/06_create_tagged_materialized_view_posts_materialized_view.rb \"here\")\n\nWith the same `notes` table with `tags` column the resulting view would have the same two columns\n\n| tag_name | taggings_count |\n|----------|----------------|\n| Ruby     | 124056         |\n| React    | 30632          |\n| Rails    | 28696          |\n| Crystal  | 6566           |\n| Elixir   | 3475           |\n\nAnd you can also create `TaggedNote` model to work with the view as with a Rails model.\n\n### Table Strategy with Triggers\n\nTBD\n\n## Inspired by\n\n1. [ActsAsTaggableOn](https://github.com/mbleigh/acts-as-taggable-on)\n2. [ActsAsTaggableArrayOn](https://github.com/tmiyamon/acts-as-taggable-array-on)\n3. [TagColumns](https://github.com/hopsoft/tag_columns)\n\n## Migration from ActsAsTaggable\n\nTo migrate your data from `ActsAsTaggable` can be done with the following migration.\n\n```ruby\nclass AddTagsToYourTable \u003c ActiveRecord::Migration[6.0]\n  def change\n    add_column :your_table, :tags, :string, array: true\n    add_index :your_table, :tags, using: 'gin'\n\n    execute \u003c\u003c~SQL\n      UPDATE your_table\n      SET tags = tags.names\n      FROM (\n        SELECT taggings.taggable_id AS your_table_id,\n               array_agg(tags.name) as names\n        FROM tags\n        INNER JOIN taggings\n                ON tags.id = taggings.tag_id\n        WHERE\n          taggings.taggable_type = 'YouTableType'\n        GROUP BY taggings.taggable_id\n      ) as tags\n      WHERE your_table.id = tags.your_table_id\n    SQL\n  end\nend\n```\n\n## Benchmark Comparison\n\nThere are some results of benchmarking a performance of write, read and find operations for different gems, that provide solution for tagging. Keep in mind, that those results can't be used as a proof, that some solution is better than the others, since each of the benchmarked gems has their unique features. You could run the benchmarks yourself or check, what exact operations has been used for benchmarking, with [MetkaBench application](https://github.com/jetrockets/metka_bench).\n\n```bash\n$ rake bench:all\nDeleted all MetkaSong\nDeleted all ActsAsTaggableOn::Tagging\nDeleted all ActsAsTaggableOn::Tag\nDeleted all ActsAsTaggableSong\nDeleted all ActsAsTaggableArraySong\nDeleted all TagColumnsSong\nFinished to clean\n\n###################################################################\n\nbench:write\n\nTime measurements:\n\nRehearsal ----------------------------------------------------------\nMetka:                   2.192410   0.161092   2.353502 (  2.754766)\nActsAsTaggableOn:       13.769918   0.554951  14.324869 ( 16.990127)\nActsAsTaggableOnArray:   2.150441   0.154127   2.304568 (  2.700022)\nTagColumns:              2.202647   0.156162   2.358809 (  2.753400)\n------------------------------------------------ total: 21.341748sec\n\n                             user     system      total        real\nMetka:                   2.137315   0.154046   2.291361 (  2.643363)\nActsAsTaggableOn:       11.302848   0.448674  11.751522 ( 14.019458)\nActsAsTaggableOnArray:   2.143134   0.128655   2.271789 (  2.670797)\nTagColumns:              2.133780   0.125749   2.259529 (  2.653404)\n\nMemory measurements:\n\nCalculating -------------------------------------\nMetka:                   179.064M memsize (     0.000  retained)\n                           1.689M objects (     0.000  retained)\n                          50.000  strings (     0.000  retained)\nActsAsTaggableOn:        843.949M memsize (     0.000  retained)\n                           8.550M objects (     0.000  retained)\n                          50.000  strings (     0.000  retained)\nActsAsTaggableOnArray:   178.807M memsize (     0.000  retained)\n                           1.684M objects (     0.000  retained)\n                          50.000  strings (     0.000  retained)\nTagColumns:              180.009M memsize (     0.000  retained)\n                           1.699M objects (     0.000  retained)\n                          50.000  strings (     0.000  retained)\n\n###################################################################\n\nbench:read\n\nTime measurements:\n\nRehearsal ----------------------------------------------------------\nMetka:                   0.479695   0.044399   0.524094 (  0.590616)\nActsAsTaggableOn:        2.436328   0.140581   2.576909 (  3.096142)\nActsAsTaggableOnArray:   0.515198   0.042127   0.557325 (  0.623205)\nTagColumns:              0.518363   0.042661   0.561024 (  0.626968)\n------------------------------------------------- total: 4.219352sec\n\n                             user     system      total        real\nMetka:                   0.446751   0.041886   0.488637 (  0.554018)\nActsAsTaggableOn:        2.395166   0.164500   2.559666 (  3.069655)\nActsAsTaggableOnArray:   0.439608   0.041682   0.481290 (  0.544679)\nTagColumns:              0.435404   0.041623   0.477027 (  0.540359)\n\nMemory measurements:\n\nCalculating -------------------------------------\nMetka:                    42.291M memsize (     0.000  retained)\n                         388.694k objects (     0.000  retained)\n                          50.000  strings (     0.000  retained)\nActsAsTaggableOn:        178.664M memsize (     0.000  retained)\n                           1.812M objects (     0.000  retained)\n                          50.000  strings (     0.000  retained)\nActsAsTaggableOnArray:    42.173M memsize (     0.000  retained)\n                         383.003k objects (     0.000  retained)\n                          50.000  strings (     0.000  retained)\nTagColumns:               41.948M memsize (     0.000  retained)\n                         383.003k objects (     0.000  retained)\n                          50.000  strings (     0.000  retained)\n\n###################################################################\n\nbench:find_by_tag\n\nTime measurements:\n\nRehearsal ----------------------------------------------------------\nMetka:                   0.029961   0.000059   0.030020 (  0.030052)\nActsAsTaggableOn:        0.067095   0.000068   0.067163 (  0.067205)\nActsAsTaggableOnArray:   0.043156   0.000133   0.043289 (  0.043440)\nTagColumns:              0.056475   0.000143   0.056618 (  0.056697)\n------------------------------------------------- total: 0.197090sec\n\n                             user     system      total        real\nMetka:                   0.028291   0.000019   0.028310 (  0.028321)\nActsAsTaggableOn:        0.065925   0.000036   0.065961 (  0.065989)\nActsAsTaggableOnArray:   0.043214   0.000079   0.043293 (  0.043361)\nTagColumns:              0.056390   0.000160   0.056550 (  0.056666)\n\nMemory measurements:\n\nCalculating -------------------------------------\nMetka:                     4.752M memsize (     0.000  retained)\n                          43.000k objects (     0.000  retained)\n                           1.000  strings (     0.000  retained)\nActsAsTaggableOn:          8.967M memsize (     0.000  retained)\n                          81.002k objects (     0.000  retained)\n                           9.000  strings (     0.000  retained)\nActsAsTaggableOnArray:     5.211M memsize (     0.000  retained)\n                          57.003k objects (     0.000  retained)\n                           6.000  strings (     0.000  retained)\nTagColumns:                6.696M memsize (     0.000  retained)\n                          94.003k objects (     0.000  retained)\n                           8.000  strings (     0.000  retained)\n\nFinished all benchmarks\n```\n\n## Development\n\nAfter checking out the repo, run `bin/setup` to install dependencies. Then, run `rake spec` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.\n\nTo install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and tags, and 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/jetrockets/metka](https://github.com/jetrockets/metka). This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the [Contributor Covenant](http://contributor-covenant.org) code of conduct.\n\n## Credits\n\n![JetRockets](https://media.jetrockets.pro/jetrockets-white.png)\nMetka is maintained by [JetRockets](http://www.jetrockets.ru).\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 Metka project’s codebases, issue trackers, chat rooms and mailing lists is expected to follow the [code of conduct](https://github.com/[USERNAME]/metka/blob/master/CODE_OF_CONDUCT.md).\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjetrockets%2Fmetka","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fjetrockets%2Fmetka","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjetrockets%2Fmetka/lists"}