🏁 FlagShihTzu
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.
👣 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 TABLEwhenever 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 | |
|---|---|
| Works with JRuby | |
| Works with Truffle Ruby | |
| Works with MRI Ruby 4 | |
| Works with MRI Ruby 3 | |
| Works with MRI Ruby 2 | |
| Support & Community | |
| Source | |
| Documentation | |
| Compliance | |
| Style | |
| Maintainer 🎖️ | |
... 💖 |
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 
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:
- Stop using the flag in application behavior, but leave it declared while old rows may still contain the bit.
- If you want to reserve the bit position, rename the flag to a tombstone name
such as
:_deprecated_shieldsand do not reuse that bit. - 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),
)
- 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
🔐 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 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 .
🌈 Contributors
Made with contributors-img.
Also see GitLab Contributors: https://gitlab.com/galtzo-floss/flag_shih_tzu/-/graphs/main
📌 Versioning
This library follows 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 .
© Copyright
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.
To say "thanks!" ☝️ Join the Discord or 👇️ send money.
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 |