{"id":18631757,"url":"https://github.com/esotericpig/attr_bool","last_synced_at":"2025-11-04T05:30:37.380Z","repository":{"id":59150814,"uuid":"256015283","full_name":"esotericpig/attr_bool","owner":"esotericpig","description":":beginner::bento::question: Finally attr_accessor \u0026 attr_reader with question marks for booleans!?","archived":false,"fork":false,"pushed_at":"2021-06-16T20:23:55.000Z","size":100,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"master","last_synced_at":"2024-04-26T00:41:11.567Z","etag":null,"topics":["attribute","attributes","attrs","bool","boolean","core-ext","core-extension","ruby","ruby-core","ruby-gem","rubygem"],"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/esotericpig.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE.txt","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2020-04-15T19:21:49.000Z","updated_at":"2021-06-16T20:22:42.000Z","dependencies_parsed_at":"2022-09-13T11:00:41.817Z","dependency_job_id":null,"html_url":"https://github.com/esotericpig/attr_bool","commit_stats":null,"previous_names":[],"tags_count":4,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/esotericpig%2Fattr_bool","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/esotericpig%2Fattr_bool/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/esotericpig%2Fattr_bool/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/esotericpig%2Fattr_bool/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/esotericpig","download_url":"https://codeload.github.com/esotericpig/attr_bool/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":239425427,"owners_count":19636346,"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":["attribute","attributes","attrs","bool","boolean","core-ext","core-extension","ruby","ruby-core","ruby-gem","rubygem"],"created_at":"2024-11-07T05:08:31.649Z","updated_at":"2025-02-18T07:21:01.799Z","avatar_url":"https://github.com/esotericpig.png","language":"Ruby","readme":"# AttrBool\n\n[![Gem Version](https://badge.fury.io/rb/attr_bool.svg)](https://badge.fury.io/rb/attr_bool)\n\n[![Source Code](https://img.shields.io/badge/source-github-%23211F1F.svg)](https://github.com/esotericpig/attr_bool)\n[![Changelog](https://img.shields.io/badge/changelog-md-%23A0522D.svg)](CHANGELOG.md)\n[![License](https://img.shields.io/github/license/esotericpig/attr_bool.svg)](LICENSE.txt)\n\nEasily create `attr` (attribute) methods that end with question marks (`?`).\n\n```Ruby\nrequire 'attr_bool'\n\nmodule Wearable\n  extend AttrBool::Ext\n\n  attr_accessor? :in_fashion\n  attr_reader?   :can_wash\nend\n\nclass BananaHammock\n  extend AttrBool::Ext\n  include Wearable\n\n  # Enforce boolean (true or false) values.\n  attr_bool  :princess\n  attr_bool? :crap_bag\nend\n\nbanham = BananaHammock.new()\n\nbanham.in_fashion = true\nbanham.princess   = true\n\np banham.in_fashion?  #=\u003e true\np banham.can_wash?    #=\u003e nil\np banham.princess?    #=\u003e true\np banham.crap_bag?    #=\u003e false\n```\n\nRequire `attr_bool/core_ext` to extend the core (monkey-patch) `Module` \u0026 `Class` (not recommended for libraries):\n\n```Ruby\nrequire 'attr_bool/core_ext'\n\nclass BananaHammock\n  attr_bool  :princess\n  attr_bool? :crap_bag\nend\n```\n\n## Contents\n\n- [Similar Projects](#-similar-projects)\n- [Setup](#-setup)\n- [Usage](#-usage)\n    - [Complete Example](#-complete-example)\n    - [Default Values](#-default-values)\n    - [Block/Proc/Lambda](#-blockproclambda)\n    - [YARDoc](#-yardoc)\n- [Hacking](#-hacking)\n    - [Benchmarks](#-benchmarks)\n- [License](#-license)\n\n## [//](#contents) Similar Projects\n\nCreate an [issue](https://github.com/esotericpig/attr_bool/issues) to add your project.\n\n| Gem Name | Code | Example |\n| --- | --- | --- |\n| [attr_asker](https://rubygems.org/gems/attr_asker) | [[GitHub]](https://github.com/kitlangton/attr_asker) | `attr_asker :running` |\n| [attr_boolean](https://rubygems.org/gems/attr_boolean) | [[GitHub]](https://github.com/talentnest/attr_boolean) | `attr_boolean :running, default: true` |\n| [attr_setting](https://rubygems.org/gems/attr_setting) | [[GitHub]](https://github.com/merhard/attr_setting) | `attr_setting :running, true` |\n| [attribool](https://rubygems.org/gems/attribool) | [[GitHub]](https://github.com/evanthegrayt/attribool) | `bool_reader :name` |\n| [attribute_boolean](https://rubygems.org/gems/attribute_boolean) | [[GitHub]](https://github.com/alexmchale/attribute_boolean) | `attr_boolean :running` |\n| [boolean_accessor](https://rubygems.org/gems/boolean_accessor) | [[GitHub]](https://github.com/hiroki23/boolean_accessor) | `battr_accessor :running` |\n| [named_accessors](https://rubygems.org/gems/named_accessors) | [[GitHub]](https://github.com/zlw/named_accessors) | `named_reader :running, as: :running?` |\n| [property-accessor](https://rubygems.org/gems/property-accessor) | [[GitHub]](https://github.com/estepnv/property-accessor) | `property(:running) { get(:running?); default { true } }` |\n| [question_mark_methods](https://rubygems.org/gems/question_mark_methods) | [[GitHub]](https://github.com/poiyzy/questionmarkmethods) | `add_question_mark_methods running?: :running` |\n| [wannabe_bool](https://rubygems.org/gems/wannabe_bool) | [[GitHub]](https://github.com/prodis/wannabe_bool) | `attr_wannabe_bool :running` |\n| [wardrobe](https://rubygems.org/gems/wardrobe) | [[GitHub]](https://github.com/agensdev/wardrobe) | `attribute :running, Wardrobe::Boolean, default: true` |\n\nSearches:\n\n- [The Ruby Toolbox](https://www.ruby-toolbox.com/search?q=attr+bool)\n- [RubyGems.org](https://rubygems.org/search?query=attr+OR+attribute)\n\n## [//](#contents) Setup\n\nAdd `attr_bool` to your *Gemspec* or *Gemfile*.\n\nOr, use the *RubyGems* package manager:\n\n```\n$ gem install attr_bool\n```\n\nOr, manually:\n\n```\n$ git clone 'https://github.com/esotericpig/attr_bool.git'\n$ cd attr_bool\n$ bundle install\n$ bundle exec rake install:local\n```\n\n## [//](#contents) Usage\n\nEither require `attr_bool` or `attr_bool/core_ext`.\n\nThe first one requires extending `AttrBool::Ext` manually.\n\n```Ruby\nrequire 'attr_bool'\n\nclass Game\n  extend AttrBool::Ext\n\n  attr_accessor? :running\n  attr_reader?   :winning\nend\n```\n\nThe second one automatically extends `Module` \u0026 `Class`, which is not recommended for sharing libraries.\n\n```Ruby\nrequire 'attr_bool/core_ext'\n\nclass Game\n  attr_accessor? :running\n  attr_reader?   :winning\nend\n```\n\nNow, simply use `attr_accessor?` and/or `attr_reader?` with one or more Symbols and/or Strings.\n\nThese do **not** force the values to be booleans (true or false).\n\nFor most purposes, this is adequate.\n\n```Ruby\nrequire 'attr_bool'\n\nclass Game\n  extend AttrBool::Ext\n\n  attr_accessor? :running,'looper'\n  attr_reader?   :fps,'music'\n\n  def initialize()\n    @running = false\n    @looper  = nil\n    @fps     = 60\n    @music   = 'Beatles'\n  end\nend\n\ngame = Game.new()\n\nputs game.running?  #=\u003e false\nputs game.looper?   #=\u003e nil\nputs game.fps?      #=\u003e 60\nputs game.music?    #=\u003e 'Beatles'\n\ngame.running = true\ngame.looper  = :main\n\nputs game.running?  #=\u003e true\nputs game.looper?   #=\u003e :main\n```\n\nThere is also `attr_writer?`, but it simply calls the standard `attr_writer` unless you pass in a [block](#-blockproclambda).\n\nTo enforce boolean (true or false) values, use...\n\n| Name | Access |\n| --- | --- |\n| `attr_bool` or `attr_boolor` | accessor |\n| `attr_bool?` | reader |\n| `attr_booler` | writer |\n\nThese are slightly slower due to always checking the values.\n\n```Ruby\nrequire 'attr_bool'\n\nclass Game\n  extend AttrBool::Ext\n\n  attr_bool   :running,'looper'\n  attr_bool?  :fps,'music'\n  attr_booler :sound\n\n  def initialize()\n    @fps   = 60\n    @music = 'Beatles'\n    @sound = false\n  end\n\n  def loud?()\n    music? \u0026\u0026 @sound == true\n  end\nend\n\ngame = Game.new()\n\nputs game.running?  #=\u003e false\nputs game.looper?   #=\u003e false\nputs game.fps?      #=\u003e true\nputs game.music?    #=\u003e true\nputs game.loud?     #=\u003e false\n\ngame.running = true\ngame.looper  = :main\ngame.sound   = 'loud!'\n\nputs game.running?  #=\u003e true\nputs game.looper?   #=\u003e true\nputs game.loud?     #=\u003e true\n```\n\n### [///](#contents) Default Values\n\nA default value can be passed in, but I don't recommend using it because it's slightly slower due to always checking the value and not setting the instance variable directly.\n\nIt's best to just set the default values the standard way in `initialize()`. However, many Gems do this, so I also added this functionality anyway.\n\nIf the last argument is not a `Symbol` or a `String`, then it will be used as the default value.\n\n**Note:** `attr_writer?` \u0026amp; `attr_booler` can **not** take in a default value.\n\n```Ruby\nrequire 'attr_bool'\n\nclass Game\n  extend AttrBool::Ext\n\n  attr_accessor? :running,:looper,false\n  attr_reader?   :min_fps,:max_fps,60\n\n  attr_bool  :gravity,:wind,true\n  attr_bool? :min_force,:max_force,110\nend\n\ngame = Game.new()\n\nputs game.running?    #=\u003e false\nputs game.looper?     #=\u003e false\nputs game.min_fps?    #=\u003e 60\nputs game.max_fps?    #=\u003e 60\nputs game.gravity?    #=\u003e true\nputs game.wind?       #=\u003e true\nputs game.min_force?  #=\u003e true (not 110)\nputs game.max_force?  #=\u003e true (not 110)\n```\n\nInstead of the last argument, you can use the `default:` keyword argument. In addition to being more clear, this allows you to pass in a `String` or a `Symbol`.\n\n```Ruby\nrequire 'attr_bool'\n\nclass Game\n  extend AttrBool::Ext\n\n  attr_accessor? :running,:looper,default: :main\n  attr_reader?   :music,:sound,default: 'quiet!'\nend\n\ngame = Game.new()\n\nputs game.running?  #=\u003e :main\nputs game.looper?   #=\u003e :main\nputs game.music?    #=\u003e 'quiet!'\nputs game.sound?    #=\u003e 'quiet!'\n```\n\n### [///](#contents) Block/Proc/Lambda\n\nA block can be passed in for dynamic values, but I don't recommend using it. However, many Gems do this, so I also added this functionality anyway.\n\nWith blocks, you can quickly write a dynamic attribute that depends on other variable(s) or tests variable(s) in some other special way.\n\n**Note:** blocks do **not** update the instance variables; you must do this manually within the block. `attr_accessor?/reader?/writer?` \u0026amp; `attr_bool*` with blocks are exactly the same code (i.e., boolean values are not enforced).\n\n```Ruby\nrequire 'attr_bool'\n\nclass Game\n  extend AttrBool::Ext\n\n  attr_reader?(:lag)  { print @ping,','; @ping \u003e 300 }\n  attr_writer?(:ping) {|value| @ping = value.to_i() }\n\n  # Define 1 block for both reader \u0026 writer together.\n  attr_accessor?(:sound) do |value=nil|\n    if value.nil? # Assume reader\n      print @sound,','\n      @sound \u003e 0\n    else # Assume writer\n      @sound = value.to_i() % 100\n    end\n  end\n\n  attr_bool?(:slow) { print @fps,','; @fps \u003c 30 }\n  attr_booler(:fps) {|value| @fps = value.to_i() }\n\n  # Define separate blocks.\n  attr_bool(:music,\n    reader: -\u003e { print @music,','; !@music.nil? },\n    writer: -\u003e(value) { @music = value.to_sym() }\n  )\n\n  # Define only 1 block.\n  attr_accessor?(:frames,\n    reader: -\u003e { @frames.odd? }\n  )\nend\n\ngame = Game.new()\n\ngame.ping   = 310.99\ngame.sound  = 199.99\ngame.fps    = 29.99\ngame.music  = 'Beatles'\ngame.frames = 1\n\nputs game.lag?     #=\u003e 310,true\nputs game.sound?   #=\u003e 99,true\nputs game.slow?    #=\u003e 29,true\nputs game.music?   #=\u003e :Beatles,true\nputs game.frames?  #=\u003e true\n```\n\n### [///](#contents) Complete Example\n\n```Ruby\nrequire 'attr_bool/core_ext'\n\nmodule Wearable\n  # +attr_accessor?/reader?+ do not enforce boolean (true or false) values.\n  attr_accessor? :in_fashion,:in_season\n  attr_reader?   :can_wash,:can_wear,default: 'yes!'\nend\n\nclass BananaHammock\n  include Wearable\n\n  # +attr_bool*+ enforce boolean (true or false) values.\n  attr_bool   :princess,:prince,default: 'Consuela'\n  attr_bool?  :can_swim,:can_wink,true\n  attr_bool? (:crap_bag) { princess? \u0026\u0026 can_swim? }\n  attr_booler :friends\n\n  def for_friends()\n    @friends\n  end\nend\n\nbanham = BananaHammock.new()\n\nputs banham.in_fashion?  #=\u003e nil\nputs banham.in_season?   #=\u003e nil\nputs banham.can_wash?    #=\u003e 'yes!'\nputs banham.can_wear?    #=\u003e 'yes!'\nputs '---'\n\nputs banham.princess?  #=\u003e true (not 'Consuela')\nputs banham.prince?    #=\u003e true (not 'Consuela')\nputs banham.can_swim?  #=\u003e true\nputs banham.can_wink?  #=\u003e true\nputs banham.crap_bag?  #=\u003e true\nputs '---'\n\nbanham.in_fashion = true\nbanham.in_season  = 'always'\nbanham.princess   = nil\nbanham.prince     = 'Charming'\nbanham.friends    = 'Valerie'\n\nputs banham.in_fashion?  #=\u003e true\nputs banham.in_season?   #=\u003e 'always'\nputs banham.princess?    #=\u003e false (not nil)\nputs banham.prince?      #=\u003e true  (not 'Charming')\nputs banham.crap_bag?    #=\u003e false (dynamic; because +princess?+ is now false)\nputs banham.for_friends  #=\u003e true  (not 'Valerie')\n```\n\n### [///](#contents) YARDoc\n\nA custom `AttributeHandler` plugin is planned for the next version:\n\n- [Writing Handlers](https://yardoc.org/guides/extending-yard/writing-handlers.html)\n- [YARD::Handlers::Ruby::AttributeHandler](https://github.com/lsegal/yard/blob/main/lib/yard/handlers/ruby/attribute_handler.rb)\n\nFor now, please use one of YARDoc's built-in ways:\n\n```Ruby\nattr_accessor? :winning # @!attribute [rw] winning=(value),winning?\nattr_reader?   :running # @!attribute [r]  running?\n\n# @!attribute [r] can_swim?\n#   @return [true,false] can you swim in it?\n# @!attribute [r] can_wink?\n#   @return [true,false] can you wink at pretty people?\nattr_reader? :can_swim,:can_wink\n\n# @!attribute [rw] princess=(value),princess?\n#   @param value [true,false] this is Ms. Consuela or not!\n#   @return [true,false] is this Ms. Consuela?\n# @!attribute [rw] crap_bag=(value),crap_bag?\n#   @param value [true,false] this is Mr. Crap Bag or not!\n#   @return [true,false] is this Mr. Crap Bag?\nattr_accessor? :princess,:crap_bag\n\n# @overload in_fashion?\n#   @return [true,false] whether it's fashionable right now\n# @overload in_fashion=(value)\n#   Make it in or out of fashion!\nattr_accessor? :in_fashion\n\n# @!method can_wear?\n# @return [true,false] whether it's wearable (default: +true+)\nattr_reader? :can_wear,true\n\n# @!group My Attrs\n# @!attribute [r] in_season?\nattr_reader? :in_season\n# @!attribute [r] can_wash?\nattr_reader? :can_wash\n# @!endgroup\n```\n\nFurther reading:\n\n- [Documenting Attributes](https://www.rubydoc.info/gems/yard/file/docs/GettingStarted.md#Documenting_Attributes)\n- [Documenting Custom DSL Methods](https://www.rubydoc.info/gems/yard/file/docs/GettingStarted.md#Documenting_Custom_DSL_Methods)\n- [Macros](https://www.rubydoc.info/gems/yard/file/docs/GettingStarted.md#Macros)\n- [Tags#Macro](https://www.rubydoc.info/gems/yard/file/docs/Tags.md#macro)\n- [Tags#Attribute](https://www.rubydoc.info/gems/yard/file/docs/Tags.md#attribute)\n\n## [//](#contents) Hacking\n\n```\n$ git clone 'https://github.com/esotericpig/attr_bool.git'\n$ cd attr_bool\n$ bundle install\n$ bundle exec rake -T\n```\n\n### Test\n\n```\n$ bundle exec rake test\n```\n\n### Generate Doc\n\n```\n$ bundle exec rake doc\n```\n\n### Install Locally\n\n```\n$ bundle exec rake install:local\n```\n\n### Release\n\n```\n$ bundle exec rake release\n```\n\n### [///](#contents) Benchmarks\n\nThere are some benchmarks that test `define_method` vs `module_eval` and `? true : false` vs `!!`.\n\nTo run these on your system:\n\n```\n$ bundle exec rake benchmark\n```\n\n## [//](#contents) License\n\n[MIT](LICENSE.txt)\n\n\u003e AttrBool (https://github.com/esotericpig/attr_bool)  \n\u003e Copyright (c) 2020-2021 Jonathan Bradley Whited  \n\u003e \n\u003e Permission is hereby granted, free of charge, to any person obtaining a copy  \n\u003e of this software and associated documentation files (the \"Software\"), to deal  \n\u003e in the Software without restriction, including without limitation the rights  \n\u003e to use, copy, modify, merge, publish, distribute, sublicense, and/or sell  \n\u003e copies of the Software, and to permit persons to whom the Software is  \n\u003e furnished to do so, subject to the following conditions:  \n\u003e \n\u003e The above copyright notice and this permission notice shall be included in all  \n\u003e copies or substantial portions of the Software.  \n\u003e \n\u003e THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR  \n\u003e IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,  \n\u003e FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE  \n\u003e AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER  \n\u003e LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,  \n\u003e OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE  \n\u003e SOFTWARE.  \n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fesotericpig%2Fattr_bool","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fesotericpig%2Fattr_bool","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fesotericpig%2Fattr_bool/lists"}