Galtzo FLOSS Logo by Aboling0, CC BY-SA 4.0 ruby-lang Logo, Yukihiro Matsumoto, Ruby Visual Identity Team, CC BY-SA 2.5 flag_shih_tzu Logo by Aboling0, CC BY-SA 4.0

🏁 FlagShihTzu

Version GitHub tag (latest SemVer) License: MIT Downloads Rank CodeCov Test Coverage Coveralls Test Coverage QLTY Test Coverage QLTY Maintainability CI Heads CI Runtime Dependencies @ HEAD CI Current CI Truffle Ruby CI JRuby Deps Locked Deps Unlocked CI Test Coverage CI Style Apache SkyWalking Eyes License Compatibility Check FOSSA Status

if ci_badges.map(&:color).detect { it != "green"} ☝️ let me know, as I may have missed the discord notification.


if ci_badges.map(&:color).all? { it == "green"} 👇️ send money so I can do more of this. FLOSS maintenance is now my full-time job.

OpenCollective Backers OpenCollective Sponsors Sponsor Me on Github Liberapay Goal Progress Donate on PayPal Buy me a coffee Donate on Polar Donate at ko-fi.com

👣 How will this project approach the September 2025 hostile takeover of RubyGems? 🚑️ I've summarized my thoughts in [this blog post](https://dev.to/galtzo/hostile-takeover-of-rubygems-my-thoughts-5hlo).

🌻 Synopsis

An extension for ActiveRecord to store a collection of boolean attributes in a single integer column as a [bit field][bit_field].

This gem lets you use a single integer column in an ActiveRecord model to store a collection of boolean attributes (flags). Each flag can be used almost in the same way you would use any boolean attribute on an ActiveRecord object.

The benefits:

  • No schema migrations needed for new boolean attributes. This helps a lot if you have very large db-tables, on which you want to avoid ALTER TABLE whenever possible. Data migrations that set newly added flags still need deploy-safe query behavior, described below.
  • Only the one integer column needs to be indexed.
  • [Bitwise Operations][bitwise_operation] are fast!

Using FlagShihTzu, you can add new boolean attributes whenever you want, without needing any migration. Just add a new flag to the has_flags call.

What is a "Shih Tzu"?

💡 Info you can shake a stick at

Tokens to Remember Gem name Gem namespace
Works with JRuby JRuby 9.2 Compat JRuby 9.3 Compat
JRuby 9.4 Compat JRuby current Compat JRuby HEAD Compat
Works with Truffle Ruby Truffle Ruby 22.3 Compat Truffle Ruby 23.0 Compat Truffle Ruby 23.1 Compat
Truffle Ruby 24.2 Compat Truffle Ruby 25.0 Compat Truffle Ruby current Compat
Works with MRI Ruby 4 Ruby 4.0 Compat Ruby current Compat Ruby HEAD Compat
Works with MRI Ruby 3 Ruby 3.0 Compat Ruby 3.1 Compat Ruby 3.2 Compat Ruby 3.3 Compat Ruby 3.4 Compat
Works with MRI Ruby 2 Ruby 2.4 Compat Ruby 2.5 Compat Ruby 2.6 Compat Ruby 2.7 Compat
Support & Community Join Me on Daily.dev's RubyFriends Live Chat on Discord Get help from me on Upwork Get help from me on Codementor
Source Source on GitLab.com Source on CodeBerg.org Source on Github.com The best SHA: dQw4w9WgXcQ!
Documentation Current release on RubyDoc.info YARD on Galtzo.com Maintainer Blog GitLab Wiki GitHub Wiki
Compliance License: MIT Apache license compatibility: Category A 📄ilo-declaration-img Security Policy Contributor Covenant 2.1 SemVer 2.0.0
Style Enforced Code Style Linter Keep-A-Changelog 1.0.0 Gitmoji Commits Compatibility appraised by: appraisal2
Maintainer 🎖️ Follow Me on LinkedIn Follow Me on Ruby.Social Follow Me on Bluesky Contact Maintainer My technical writing
... 💖 Find Me on WellFound: Find Me on CrunchBase My LinkTree More About Me 🧊 🐙 🛖 🧪

Compatibility

Compatible with MRI Ruby 2.4+, and concordant releases of JRuby, and TruffleRuby. CI workflows and Appraisals are generated for MRI Ruby 2.4+. This test floor is configured by ruby.test_minimum in .kettle-jem.yml and may be higher than the gem's runtime compatibility floor when legacy Rubies are not practical for the current toolchain.

🚚 Amazing test matrix was brought to you by 🔎 appraisal2 🔎 and the color 💚 green 💚
👟 Check it out! github.com/appraisal-rb/appraisal2

Federated DVCS

Find this repo on federated forges (Coming soon!) | Federated [DVCS][💎d-in-dvcs] Repository | Status | Issues | PRs | Wiki | CI | Discussions | |-------------------------------------------------|-----------------------------------------------------------------------|---------------------------|--------------------------|---------------------------|--------------------------|------------------------------| | 🧪 [galtzo-floss/flag_shih_tzu on GitLab][📜src-gl] | The Truth | [💚][🤝gl-issues] | [💚][🤝gl-pulls] | [💚][📜gl-wiki] | 🐭 Tiny Matrix | ➖ | | 🧊 [galtzo-floss/flag_shih_tzu on CodeBerg][📜src-cb] | An Ethical Mirror ([Donate][🤝cb-donate]) | [💚][🤝cb-issues] | [💚][🤝cb-pulls] | ➖ | ⭕️ No Matrix | ➖ | | 🐙 [galtzo-floss/flag_shih_tzu on GitHub][📜src-gh] | Another Mirror | [💚][🤝gh-issues] | [💚][🤝gh-pulls] | [💚][📜gh-wiki] | 💯 Full Matrix | [💚][gh-discussions] | | 🎮️ [Discord Server][✉️discord-invite] | [![Live Chat on Discord][✉️discord-invite-img-ftb]][✉️discord-invite] | [Let's][✉️discord-invite] | [talk][✉️discord-invite] | [about][✉️discord-invite] | [this][✉️discord-invite] | [library!][✉️discord-invite] |

Enterprise Support Tidelift

Available as part of the Tidelift Subscription.

Need enterprise-level guarantees? The maintainers of this and thousands of other packages are working with Tidelift to deliver commercial support and maintenance for the open source packages you use to build your applications. Save time, reduce risk, and improve code health, while paying the maintainers of the exact packages you use. [![Get help from me on Tidelift][🏙️entsup-tidelift-img]][🏙️entsup-tidelift] - 💡Subscribe for support guarantees covering _all_ your FLOSS dependencies - 💡Tidelift is part of [Sonar][🏙️entsup-tidelift-sonar] - 💡Tidelift pays maintainers to maintain the software you depend on!
📊`@`Pointy Haired Boss: An [enterprise support][🏙️entsup-tidelift] subscription is "[never gonna let you down][🧮kloc]", and *supports* open source maintainers Alternatively: - [![Live Chat on Discord][✉️discord-invite-img-ftb]][✉️discord-invite] - [![Get help from me on Upwork][👨🏼‍🏫expsup-upwork-img]][👨🏼‍🏫expsup-upwork] - [![Get help from me on Codementor][👨🏼‍🏫expsup-codementor-img]][👨🏼‍🏫expsup-codementor]

✨ Installation

Install the gem and add to the application's Gemfile by executing:

bundle add flag_shih_tzu

If bundler is not being used to manage dependencies, install the gem by executing:

gem install flag_shih_tzu

⚙️ Configuration

🔧 Basic Usage

FlagShihTzu assumes that your ActiveRecord model already has an [integer field][bit_field] to store the flags, which should be defined to not allow NULL values and should have a default value of 0.

Defaults (Important)

  • Due to the default of 0, all flags are initially set to "false").
  • For a default of true it will probably be easier in the long run to negate the flag's meaning / name. ** Such as switched_on => switched_off
  • If you really want a different, non-zero, default value for a flag column, proceed adroitly with a different sql default for the flag column.

Database Migration

I like to document the intent of the flags column in the migration when I can...

change_table :spaceships do |t|
  t.integer(:flags, null: false, default: 0) # flag_shih_tzu-managed bit field
  # Effective booleans which will be stored on the flags column:
  # t.boolean      :warpdrive
  # t.boolean      :shields
  # t.boolean      :electrolytes
end

Adding to the Model

class Spaceship < ActiveRecord::Base
  include FlagShihTzu

  has_flags 1 => :warpdrive,
    2 => :shields,
    3 => :electrolytes
end

has_flags takes a hash. The keys must be positive integers and represent the position of the bit being used to enable or disable the flag. The keys must not be changed once in use, or you will get incorrect results. That is why the plugin forces you to set them explicitly. The values are symbols for the flags being created.

If a flag name conflicts with an existing instance method, has_flags raises an error by default. To intentionally replace the existing method with FlagShihTzu's generated flag methods, pass :allow_overwrite => true:

has_flags 1 => :warpdrive,
  :allow_overwrite => true

Bit Fields: How it stores the values

As said, FlagShihTzu uses a single integer column to store the values for all the defined flags as a [bit field][bitfield].

The bit position of a flag corresponds to the given key.

This way, we can use [bitwise operators][bit_operation] on the stored integer value to set, unset and check individual flags.

              `---+---+---+                +---+---+---`
              |   |   |   |                |   |   |   |
Bit position  | 3 | 2 | 1 |                | 3 | 2 | 1 |
(flag key)    |   |   |   |                |   |   |   |
              `---+---+---+                +---+---+---`
              |   |   |   |                |   |   |   |
Bit value     | 4 | 2 | 1 |                | 4 | 2 | 1 |
              |   |   |   |                |   |   |   |
              `---+---+---+                +---+---+---`
              | e | s | w |                | e | s | w |
              | l | h | a |                | l | h | a |
              | e | i | r |                | e | i | r |
              | c | e | p |                | c | e | p |
              | t | l | d |                | t | l | d |
              | r | d | r |                | r | d | r |
              | o | s | i |                | o | s | i |
              | l |   | v |                | l |   | v |
              | y |   | e |                | y |   | e |
              | t |   |   |                | t |   |   |
              | e |   |   |                | e |   |   |
              | s |   |   |                | s |   |   |
              `---+---+---+                +---+---+---`
              | 1 | 1 | 0 | = 4 ` 2 = 6    | 1 | 0 | 1 | = 4 ` 1 = 5
              `---+---+---+                +---+---+---`

Read more about [bit fields][bit_field] here: http://en.wikipedia.org/wiki/Bit_field

Flag value modes and custom encoders

By default, each flag uses boolean mode. This keeps the historical one-bit storage format unchanged:

has_flags 1 => :warpdrive,
  2 => :shields

This is equivalent to:

has_flags(
  {1 => :warpdrive, 2 => :shields},
  value_mode: :boolean,
)

For flags that need true, false, and nil, use tri-state mode:

has_flags(
  {1 => :warpdrive, 2 => :shields},
  value_mode: :tri_state,
)

With value_mode: :tri_state, each flag is encoded in its own two-bit slot. A flag can be enabled, disabled, or cleared to nil:

enterprise.warpdrive = true
enterprise.shields = nil

enterprise.warpdrive      # true
enterprise.shields        # nil
enterprise.shields_nil?   # true

Generated SQL helpers also understand the nil state:

Spaceship.warpdrive_condition      # flags & 3 = 1
Spaceship.not_warpdrive_condition  # flags & 3 = 0
Spaceship.warpdrive_nil_condition  # flags & 3 = 3
Spaceship.clear_warpdrive_sql      # clears the two-bit slot to nil

Changing an existing flag column from one-bit boolean storage to two-bit tri-state storage changes the meaning of stored integers. Treat that as a data migration, not a model-only change.

Applications with specialized storage needs can provide a custom encoder:

has_flags(
  {1 => :warpdrive},
  bit_width: 2,
  encoder: MyFlagEncoder,
)

The built-in value modes cover boolean one-bit storage and tri-state two-bit storage. You can still pass bit_width: 1 or bit_width: 2 directly, but value_mode: :boolean and value_mode: :tri_state are the preferred public API. If you set bit_width: 3 or higher, you must provide an encoder so FlagShihTzu does not guess what the extra states mean.

Using a custom column name

The default column name to store the flags is flags, but you can provide a custom column name using the :column option. This allows you to use different columns for separate flags:

has_flags 1 => :warpdrive,
  2 => :shields,
  3 => :electrolytes,
  :column => "features"

has_flags 1 => :spock,
  2 => :scott,
  3 => :kirk,
  :column => "crew"

Generated boolean patterned instance methods

Calling has_flags, as shown above on the 'features' column, creates the following instance methods on Spaceship:

Spaceship#all_features # [:warpdrive, :shields, :electrolytes]
Spaceship#selected_features
Spaceship#select_all_features
Spaceship#unselect_all_features
Spaceship#selected_features=
Spaceship#features_as_attributes

Spaceship#warpdrive
Spaceship#warpdrive?
Spaceship#warpdrive=
Spaceship#not_warpdrive
Spaceship#not_warpdrive?
Spaceship#not_warpdrive=
Spaceship#warpdrive_changed?
Spaceship#has_warpdrive?

Spaceship#shields
Spaceship#shields?
Spaceship#shields=
Spaceship#not_shields
Spaceship#not_shields?
Spaceship#not_shields=
Spaceship#shields_changed?
Spaceship#has_shield?

Spaceship#electrolytes
Spaceship#electrolytes?
Spaceship#electrolytes=
Spaceship#not_electrolytes
Spaceship#not_electrolytes?
Spaceship#not_electrolytes=
Spaceship#electrolytes_changed?
Spaceship#has_electrolyte?

Callbacks and Validations

Optionally, you can set the :bang_methods option to true to also define the bang methods:

Spaceship#electrolytes!     # will save the bitwise equivalent of electrolytes = true on the record
Spaceship#not_electrolytes! # will save the bitwise equivalent of electrolytes = false on the record

which respectively enables or disables the electrolytes flag.

The :bang_methods does not save the records to the database, meaning it cannot engage validations and callbacks.

Alternatively, if you do want to save a flag to the database, while still avoiding validations and callbacks, use update_flag! which:

  • sets a flag on a database record without triggering callbacks or validations
  • optionally syncs the ruby instance with new flag value, by default it does not.

Example:

update_flag!(flag_name, flag_value, update_instance = false)

Generated class methods

Calling has_flags as shown above creates the following class methods on Spaceship:

Spaceship.flag_columns      # [:features, :crew]

Generated named scopes

The following named scopes become available:

Spaceship.warpdrive         # :conditions => "(spaceships.flags & 1 = 1)"
Spaceship.not_warpdrive     # :conditions => "(spaceships.flags & 1 = 0)"
Spaceship.shields           # :conditions => "(spaceships.flags & 2 = 2)"
Spaceship.not_shields       # :conditions => "(spaceships.flags & 2 = 0)"
Spaceship.electrolytes      # :conditions => "(spaceships.flags & 4 = 4)"
Spaceship.not_electrolytes  # :conditions => "(spaceships.flags & 4 = 0)"

If you do not want the named scopes to be defined, set the :named_scopes option to false when calling has_flags:

has_flags 1 => :warpdrive, 2 => :shields, 3 => :electrolytes, :named_scopes => false

In a Rails 3+ application, FlagShihTzu will use scope internally to generate the scopes. The option on has_flags is still named :named_scopes however.

Examples for using the generated methods

enterprise = Spaceship.new
enterprise.warpdrive = true
enterprise.shields = true
enterprise.electrolytes = false
enterprise.save

if enterprise.shields?
  # ...
end

Spaceship.warpdrive.find(:all)
Spaceship.not_electrolytes.count

Setting multiple flags through the column

The flag column writer accepts raw integer values, arrays, and hashes. Raw integers are still written directly:

enterprise.flags = 5

Assigning an array sets the column to exactly that selected set of flags:

enterprise.update!(flags: [:warpdrive, :electrolytes])

Unmentioned flags are disabled. You can also include :not_<flag> tokens:

enterprise.flags = [:warpdrive, :not_shields]

Assigning a hash updates only the mentioned flags and preserves the rest:

enterprise.flags = {
  warpdrive: true,
  shields: false,
}

Custom flag columns support the same forms through their column writer:

enterprise.features = [:warpdrive]
enterprise.crew = {spock: true, kirk: false}

Reading flags as attributes

Flag values can be read as a hash of boolean attributes:

enterprise.warpdrive = true
enterprise.shields = false

enterprise.flags_as_attributes
# {:warpdrive => true, :shields => false, :electrolytes => false}

For a custom flag column, either pass the column name or use the generated column-specific helper:

enterprise.flags_as_attributes("features")
enterprise.features_as_attributes

If you want Active Record's normal attributes plus the virtual flag attributes, use attributes_with_flags:

enterprise.attributes_with_flags
# {"id" => 1, "features" => 1, "warpdrive" => true, "shields" => false, ...}

Support for manually building conditions

The following class methods may support you when manually building ActiveRecord conditions:

Spaceship.warpdrive_condition         # "(spaceships.flags & 1 = 1)"
Spaceship.not_warpdrive_condition     # "(spaceships.flags & 1 = 0)"
Spaceship.shields_condition           # "(spaceships.flags & 2 = 2)"
Spaceship.not_shields_condition       # "(spaceships.flags & 2 = 0)"
Spaceship.electrolytes_condition      # "(spaceships.flags & 4 = 4)"
Spaceship.not_electrolytes_condition  # "(spaceships.flags & 4 = 0)"

These methods also accept a :table_alias option that can be used when generating SQL that references the same table more than once:

Spaceship.shields_condition(table_alias: "evil_spaceships") # "(evil_spaceships.flags & 2 = 2)"

Choosing a query mode

By default, FlagShihTzu builds SQL conditions with bit operators:

Spaceship.warpdrive_condition # "(spaceships.flags & 1 = 1)"

This is the safest default when flags are added over time. An IN() list can only match the flag combinations known to the currently running process. During a rolling deploy, old application processes may still know about only these flags:

has_flags 1 => :warpdrive,
  2 => :shields

Those old processes would build a :warpdrive condition like flags in (1,3). If the new deploy adds 3 => :premium and a migration sets that new bit on existing rows, a row with warpdrive and premium becomes flags = 5. The old IN() condition no longer matches it even though the warpdrive bit is still set. A bit-operator condition such as flags & 1 = 1 continues to match the row correctly.

The drawback is that due to the [bitwise operation][bitwise_operation] being done on the SQL side, this query may not use an index on the flags column as effectively as a small IN() list.

If your application values that query shape and you can guarantee that new flags are not set while old app code may still be running, you can opt back into the legacy mode globally:

FlagShihTzu.default_flag_query_mode = :in_list

Or per has_flags declaration:

has_flags 1 => :warpdrive,
  2 => :shields,
  :flag_query_mode => :in_list

The legacy :in_list mode may perform well for a small fixed set of flags, but it does not work well for a high number of flags, as the value list for IN() grows.

For MySQL, depending on your MySQL settings, this can even hit the max_allowed_packet limit with the generated query, or the similar query length maximum for PostgreSQL.

The :bit_operator mode remains available explicitly:

has_flags 1 => :warpdrive,
  2 => :shields,
  :flag_query_mode => :bit_operator

This will modify the generated condition and named_scope methods to use bit operators in the SQL instead of an IN() list:

Spaceship.warpdrive_condition     # "(spaceships.flags & 1 = 1)",
Spaceship.not_warpdrive_condition # "(spaceships.flags & 1 = 0)",
Spaceship.shields_condition       # "(spaceships.flags & 2 = 2)",
Spaceship.not_shields_condition   # "(spaceships.flags & 2 = 0)",

Spaceship.warpdrive     # :conditions => "(spaceships.flags & 1 = 1)"
Spaceship.not_warpdrive # :conditions => "(spaceships.flags & 1 = 0)"
Spaceship.shields       # :conditions => "(spaceships.flags & 2 = 2)"
Spaceship.not_shields   # :conditions => "(spaceships.flags & 2 = 0)"

Deprecating or removing flags

Flag values are stored as bits in one integer. Removing a flag from the has_flags declaration does not clear that bit from existing rows.

For example, an old version of the model may have this declaration:

has_flags 1 => :warpdrive,
  2 => :shields

If a row has both flags enabled, its integer value is 3. If a later version of the model removes :shields:

has_flags 1 => :warpdrive

the row still has flags = 3. With the default :bit_operator query mode, Spaceship.warpdrive still matches that row because it asks whether bit 1 is set. With legacy :in_list mode, the same scope would only know about the remaining :warpdrive flag and would generate a value-list query equivalent to flags in (1), which would not match the row.

Recommended removal path:

  1. Stop using the flag in application behavior, but leave it declared while old rows may still contain the bit.
  2. If you want to reserve the bit position, rename the flag to a tombstone name such as :_deprecated_shields and do not reuse that bit.
  3. If you want to remove the bit entirely, deploy a data cleanup while the flag is still declared:
Spaceship.where(Spaceship.shields_condition).update_all(
  Spaceship.set_flag_sql(:shields, false),
)
  1. After the cleanup has run everywhere and no old app processes still refer to the flag, remove it from has_flags.

Do not reuse a removed flag's bit position for a different meaning unless you have first cleared that bit from every persisted row. Reusing uncleared bits turns old data into false positives for the new flag.

Updating flag column by raw sql

If you need to do mass updates without initializing object for each row, you can use #set_flag_sql method on your class. Example:

Spaceship.set_flag_sql(:warpdrive, true) # "flags = flags | 1"
Spaceship.set_flag_sql(:shields, false)  # "flags = flags & ~2"

And then use it in:

Spaceship.update_all(Spaceship.set_flag_sql(:shields, false))

Beware that using multiple flag manipulation sql statements in the same query probably will not have the desired effect (at least on sqlite3, not tested on other databases), so you should not do this:

Spaceship.update_all("#{Spaceship.set_flag_sql(:shields, false)},#{
  Spaceship.set_flag_sql(:warpdrive, true)}")

General rule of thumb: issue only one flag update per update statement.

Checking flag columns

By default, has_flags does not check the database while the model class is being loaded. This keeps model loading safe during tasks such as db:create, db:migrate, db:setup, db:seed, asset precompilation, and test bootstraps where the database or table may not exist yet.

If you want has_flags to verify that the flag column exists and is an integer when the model is loaded, opt in per declaration:

has_flags 1 => :warpdrive,
  2 => :shields,
  :check_for_column => true

Or opt in globally before models are loaded:

FlagShihTzu.default_check_for_column = true

🧪 Running the gem tests

The current test harness is RSpec/Combustion based:

bin/rake spec

For appraisal-specific checks, run through Appraisal with Appraisal.root.gemfile so Bundler does not load the root development Gemfile:

BUNDLE_GEMFILE=Appraisal.root.gemfile bundle exec appraisal kja-ar-8-0-r3 bundle exec kettle-test

Older development workflows used bin/test.bash, RVM, and hand-managed database setup. That script is still present for historical reference, but the templated CI path is now the Appraisal/RSpec flow.

👥 Authors

Peter Boling, Patryk Peszko, Sebastian Roebke, David Anderson, Tim Payton and a helpful group of contributors. Thanks!

Find out more about Peter Boling's work at RailsBling.com.

Find out more about XING at their Devblog.

🛠 How you can help!

Take a look at the REEK backlog and start fixing things. Once you complete a change, run the tests. See "Running the gem tests".

If the tests pass, refresh the REEK backlog through the rake task:

bin/rake reek:update

Follow the instructions in "Contributing" below.

🕰 2012 Change of Ownership and 0.3.X Release Notes

FlagShihTzu was originally a XING AG project. Peter Boling was a long time contributor and watcher of the project.

In September 2012 XING transferred ownership of the project to Peter Boling. Peter Boling had been maintaining a fork with extended capabilities. These additional features became a part of the 0.3 line. The 0.2 line of the gem will remain true to XING's original. The 0.3 line aims to maintain complete parity and compatibility with XING's original as well. I will continue to monitor other forks for original ideas and improvements. Pull requests are welcome, but please rebase your work onto the current main branch to make integration easier.

More information on the changes for 0.3.X: galtzo-floss/flag_shih_tzu/wiki/Changes-for-0.3.x

Alternatives

I discovered in October 2015 that Michael Grosser had created a competing tool, bitfields, way back in 2010, exactly a year after this tool was created. It was a very surreal moment, as I had thought this was the only game in town and it was when I began using and hacking on it. Once I got over that moment I became excited, because competition makes things better, right? So, now I am looking forward to a shootout some lazy Saturday. Until then there's this: https://railsbling.com/flag_shih_tzu/why-use-flag_shih_tzu/

There is little that bitfields does better. The code is less efficient, albeit more readable, not as well tested, has almost zero inline documentation, and simply can't do many of the things I've built into flag_shih_tzu. If you are still on legacy Ruby or legacy Rails, or using JRuby, then use flag_shih_tzu. If you need multiple flag columns on a single model, use flag_shih_tzu.

Will there ever be a merb/rails-like love fest between the projects? It would be interesting. I like his name better. I like my features better. I like some of his code better, and some of my code better. I've been wanting to do a full rewrite of flag_shih_tzu ever since I inherited the project from XING, but I haven't had time. So I don't know.

🦷 FLOSS Funding

While galtzo-floss tools are free software and will always be, the project would benefit immensely from some funding. Raising a monthly budget of... "dollars" would make the project more sustainable.

We welcome both individual and corporate sponsors! We also offer a wide array of funding channels to account for your preferences. Currently, Open Collective is our preferred funding platform.

If you're working in a company that's making significant use of galtzo-floss tools we'd appreciate it if you suggest to your company to become a galtzo-floss sponsor.

You can support the development of galtzo-floss tools via GitHub Sponsors, Liberapay, PayPal, Open Collective and Tidelift.

📍 NOTE
If doing a sponsorship in the form of donation is problematic for your company
from an accounting standpoint, we'd recommend the use of Tidelift,
where you can get a support-like subscription instead.

Open Collective for Individuals

Support us with a monthly donation and help us continue our activities. [Become a backer]

NOTE: kettle-readme-backers updates this list every day, automatically.

No backers yet. Be the first!

Open Collective for Organizations

Become a sponsor and get your logo on our README on GitHub with a link to your site. [Become a sponsor]

NOTE: kettle-readme-backers updates this list every day, automatically.

No sponsors yet. Be the first!

Another way to support open-source

I’m driven by a passion to foster a thriving open-source community – a space where people can tackle complex problems, no matter how small. Revitalizing libraries that have fallen into disrepair, and building new libraries focused on solving real-world challenges, are my passions. I was recently affected by layoffs, and the tech jobs market is unwelcoming. I’m reaching out here because your support would significantly aid my efforts to provide for my family, and my farm (11 🐔 chickens, 2 🐶 dogs, 3 🐰 rabbits, 8 🐈‍ cats).

If you work at a company that uses my work, please encourage them to support me as a corporate sponsor. My work on gems you use might show up in bundle fund.

I’m developing a new library, floss_funding, designed to empower open-source developers like myself to get paid for the work we do, in a sustainable way. Please give it a look.

Floss-Funding.dev: 👉️ No network calls. 👉️ No tracking. 👉️ No oversight. 👉️ Minimal crypto hashing. 💡 Easily disabled nags

OpenCollective Backers OpenCollective Sponsors Sponsor Me on Github Liberapay Goal Progress Donate on PayPal Buy me a coffee Donate on Polar Donate to my FLOSS efforts at ko-fi.com Donate to my FLOSS efforts using Patreon

🔐 Security

See SECURITY.md.

🤝 Contributing

If you need some ideas of where to help, you could work on adding more code coverage, or if it is already 💯 (see below) check issues or PRs, or use the gem and think about how it could be better.

We Keep A Changelog so if you make changes, remember to update it.

See CONTRIBUTING.md for more detailed instructions.

🚀 Release Instructions

See CONTRIBUTING.md.

Code Coverage

Coverage service badges [![Coverage Graph][🏀codecov-g]][🏀codecov] [![Coveralls Test Coverage][🏀coveralls-img]][🏀coveralls] [![QLTY Test Coverage][🏀qlty-covi]][🏀qlty-cov]

🪇 Code of Conduct

Everyone interacting with this project's codebases, issue trackers, chat rooms and mailing lists agrees to follow the Contributor Covenant 2.1.

🌈 Contributors

Contributors

Made with contributors-img.

Also see GitLab Contributors: https://gitlab.com/galtzo-floss/flag_shih_tzu/-/graphs/main

⭐️ Star History Star History Chart

📌 Versioning

This library follows Semantic Versioning 2.0.0 for its public API where practical. For most applications, prefer the Pessimistic Version Constraint with two digits of precision.

For example:

spec.add_dependency("flag_shih_tzu", "~> 0.0")
📌 Is "Platform Support" part of the public API? More details inside. Dropping support for a platform can be a breaking change for affected users. If a release changes supported platforms, it should be called out clearly in the changelog and versioned with that impact in mind. To get a better understanding of how SemVer is intended to work over a project's lifetime, read this article from the creator of SemVer: - ["Major Version Numbers are Not Sacred"][📌major-versions-not-sacred]

See CHANGELOG.md for a list of releases.

📄 License

The gem is available as open source under the terms of the MIT License: MIT.

See LICENSE.md for the official copyright notice.

Copyright holders - Copyright (c) 2009 Alto - Copyright (c) 2009-2012 boosty - Copyright (c) 2009-2010 Daniel Jagszent - Copyright (c) 2009-2010 ladislav.martincik - Copyright (c) 2009 Martin Stannard - Copyright (c) 2009-2011 pboling - Copyright (c) 2009 Sebastian Roebke - Copyright (c) 2009 Tobias Bielohlawek - Copyright (c) 2009 XING Engineering - Copyright (c) 2010 Joost Baaij - Copyright (c) 2010 Joost Baaij - Copyright (c) 2010 Ryan Wallace - Copyright (c) 2011 Arturas Slajus - Copyright (c) 2011 Musy Bite - Copyright (c) 2011, 2014 Tim Liner - Copyright (c) 2012-2013 David DIDIER - Copyright (c) 2012-2015, 2017-2018, 2026 Peter H. Boling - Copyright (c) 2012 Tatsuhiko Miyagawa - Copyright (c) 2013 Blake Thomson - Copyright (c) 2013 Keith Pitty - Copyright (c) 2013 Peter M. Goldstein - Copyright (c) 2013 Thomas Jachmann - Copyright (c) 2014 Alexander Tipugin - Copyright (c) 2014, 2017-2018, 2025 Jonathan del Strother - Copyright (c) 2015 Ivan - Copyright (c) 2015 jfcaiceo - Copyright (c) 2016 Xinran Xiao - Copyright (c) 2017 shiro16 - Copyright (c) 2018 Peter Boling - Copyright (c) 2018 xpol - Copyright (c) 2018 Yusuke Ebihara - Copyright (c) 2019 Amy Martin - Copyright (c) 2025 Annibelle Boling - Copyright (c) 2025 horiken

🤑 A request for help

Maintainers have teeth and need to pay their dentists. After getting laid off in an RIF in March, and encountering difficulty finding a new one, I began spending most of my time building open source tools. I'm hoping to be able to pay for my kids' health insurance this month, so if you value the work I am doing, I need your support. Please consider sponsoring me or the project.

To join the community or get help 👇️ Join the Discord.

Live Chat on Discord

To say "thanks!" ☝️ Join the Discord or 👇️ send money.

Sponsor galtzo-floss/flag_shih_tzu on Open Source Collective 💌 Sponsor me on GitHub Sponsors 💌 Sponsor me on Liberapay 💌 Donate on PayPal

Please give the project a star ⭐ ♥.

Thanks for RTFM. ☺️

Field Value
Package flag_shih_tzu
Description 🏁 Bit fields for ActiveRecord:
This gem lets you use a single integer column in an ActiveRecord model
to store a collection of boolean attributes (flags). Each flag can be used
almost in the same way you would use any boolean attribute on an
ActiveRecord object.
Homepage https://github.com/galtzo-floss/flag_shih_tzu
Source https://github.com/galtzo-floss/flag_shih_tzu/tree/v0.3.23
License MIT
Funding https://github.com/sponsors/pboling, https://issuehunt.io/u/pboling, https://ko-fi.com/pboling, https://liberapay.com/pboling/donate, https://patreon.com/galtzo, https://polar.sh/pboling, https://thanks.dev/u/gh/pboling, https://tidelift.com/funding/github/rubygems/flag_shih_tzu, https://www.buymeacoffee.com/pboling