Skip to content

πŸ”°πŸ±β“ Finally attr_accessor & attr_reader with question marks for booleans/predicates!?

License

Notifications You must be signed in to change notification settings

esotericpig/attr_bool

Folders and files

NameName
Last commit message
Last commit date

Latest commit

Β 

History

78 Commits
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

Repository files navigation

AttrBool

Gem Version Tests Status Source Code Changelog License

Easily create attr (attribute) methods that end with question marks (?) for booleans/predicates.

require 'attr_bool'

class TheTodd
  extend AttrBool::Ext
  #using AttrBool::Ref  # Can use refinements instead.

  attr_accessor? :headband
  attr_reader?   :banana_hammock
  attr_writer?   :high_five

  # Can do DSL chaining.
  protected attr_accessor? :carla_kiss, :elliot_kiss

  # Can force bool values (i.e., only `true` or `false`).
  attr_bool      :bounce_pecs  # Accessor.
  attr_bool?     :cat_fight    # Reader.
  attr_bool!     :hot_tub      # Writer.
end

todd = TheTodd.new

puts todd.headband?
puts todd.banana_hammock?
puts todd.bounce_pecs?
puts todd.cat_fight?

Features:

  • Can use multiple symbols and/or strings.
  • Can force bool values.
  • Can define custom logic with a block/proc.
  • Can do DSL chaining, just like the core attr methods that return an array of the new method names.
  • Can use refinements (using AttrBool::Ref) instead of extend.
  • Fails fast if an instance variable name is invalid (if you don't use a block/proc).

Anti-features:

  • No default values.
    • Initialize your instance variables in def initialize like normal.
    • Using default values has performance/memory issues and other drawbacks, so better to just match the core attr methods.
  • Uses inner AttrBool::Ext & AttrBool::Ref instead of AttrBool.
    • Some gems use the extend AttrBool (top module) pattern, but this includes VERSION in all of your classes/modules.
  • Doesn't monkey-patch the core class/module by default.
    • If desired for apps/scripts, you still can with require 'attr_bool/core_ext', but not recommended for libraries.

// Contents

// Similar Projects

Create a discussion or an issue to let me know to add your project.

Gem Name Code Example
attr_asker GitHub attr_asker :winning
attr_boolean GitHub attr_boolean :winning, default: true
attr_setting GitHub attr_setting :winning, true
attribool GitHub bool_reader :winning
attribute_boolean GitHub attr_boolean :winning
attribute_predicates GitHub attr :winning, true
boolean_accessor GitHub battr_accessor :winning
named_accessors GitHub named_reader :winning, as: :winning?
predicateable GitHub predicate :wins, [:losing, :winning]
predicates GitHub predicate :winning?
property-accessor GitHub property(:winning) { get(:winning?); default { true } }
question_mark_methods GitHub add_question_mark_methods winning?: :winning
wannabe_bool GitHub attr_wannabe_bool :winning
wardrobe GitHub attribute :winning, Wardrobe::Boolean, default: true

Searches:

Site Searches
The Ruby Toolbox 1, 2
RubyGems.org 1, 2

// Setup

Pick your poison...

With the RubyGems package manager:

gem install attr_bool

Or in your Gemspec:

spec.add_dependency 'attr_bool', '~> X.X'

Or in your Gemfile:

# Pick your poison...
gem 'attr_bool', '~> X.X'
gem 'attr_bool', git: 'https://github.com/esotericpig/attr_bool.git'

Or from source:

git clone --depth 1 'https://github.com/esotericpig/attr_bool.git'
cd attr_bool
bundle install
bundle exec rake install:local

// Usage

You can either add extend AttrBool::Ext in your class/module, add using AttrBool::Ref in your class/module, or include require 'attr_bool/core_ext'.

require 'attr_bool'

class TheTodd
  extend AttrBool::Ext
  #using AttrBool::Ref  # Can use refinements instead.

  # Can use multiple symbols and/or strings.
  attr_accessor? :flexing, 'bounce_pecs'

  # Can do DSL chaining.
  protected attr_accessor? :high_five, 'fist_bump'

  # Can do custom logic.
  attr_accessor? :headband, 'banana_hammock',
                 reader: -> { @wearing == :flaming },
                 writer: ->(value) { @wearing = value }

  attr_reader?(:cat_fights)    { @cat_fights % 69 }
  attr_writer?(:hot_surgeries) { |count| @hot_surgeries += count }

  # Can force bool values (i.e., only `true` or `false`).
  attr_bool  :carla_kiss   # Accessor.
  attr_bool? :elliot_kiss  # Reader.
  attr_bool! :thumbs_up    # Writer.
end

If you don't want to have to add extend AttrBool::Ext to every inner class/module (within the same file), then you can simply refine the outer module or the file:

require 'attr_bool'

#using AttrBool::Ref  # Can refine the entire file instead (doesn't affect other files).

module TheToddMod
  using AttrBool::Ref

  class TheTodd
    attr_bool :banana_hammock
  end

  class TheToddBod
    attr_bool :bounce_pecs
  end
end

If you only have an app/script (not a library), then you can simply include require 'attr_bool/core_ext' to monkey-patch the core class & module:

require 'attr_bool/core_ext'

class TheTodd
  attr_bool :banana_hammock
end

/// RuboCop

RuboCop might complain about Layout/EmptyLinesAroundAttributeAccessor:

class TheTodd
  attr_accessor? :banana_hammock
  attr_accessor  :headband
  attr_accessor? :bounce_pecs
end

You can either disable this Cop or adjust it accordingly:

Layout/EmptyLinesAroundAttributeAccessor:
  #Enabled: false
  AllowedMethods:
    - attr_accessor?
    - attr_reader?
    - attr_writer?
    - attr_bool
    - attr_bool?
    - attr_bool!

/// YARDoc

Here are some examples of how to document the methods in YARDoc:

attr_accessor? :winning # @!attribute [rw] winning=(value),winning?
attr_reader?   :running # @!attribute [r]  running?

# @!attribute [r] can_swim?
#   @return [true,false] can you swim in it?
# @!attribute [r] can_wink?
#   @return [true,false] can you wink at pretty people?
attr_reader? :can_swim,:can_wink

# @!attribute [rw] princess=(value),princess?
#   @param value [true,false] this is Ms. Consuela or not!
#   @return [true,false] is this Ms. Consuela?
# @!attribute [rw] crap_bag=(value),crap_bag?
#   @param value [true,false] this is Mr. Crap Bag or not!
#   @return [true,false] is this Mr. Crap Bag?
attr_accessor? :princess,:crap_bag

# @overload in_fashion?
#   @return [true,false] whether it's fashionable right now
# @overload in_fashion=(value)
#   Make it in or out of fashion!
attr_accessor? :in_fashion

# @!group My Attrs
# @!attribute [r] in_season?
attr_reader? :in_season
# @!attribute [r] can_wash?
attr_reader? :can_wash
# @!endgroup

Further reading:

// Hacking

git clone 'https://github.com/esotericpig/attr_bool.git'
cd attr_bool
bundle install
bundle exec rake -T

Run tests:

bundle exec rake test

Generate doc:

bundle exec rake doc

Install locally:

bundle exec rake install:local

/// Benchmarks

Benchmarks are kind of meaningless, but after playing around with some, I found the following to be true on my system:

  • define_method() is faster than class/module_eval().
  • ? true : false (ternary operator) is faster than !! (surprisingly).

Therefore, AttrBool uses the "faster" ones found.

To run these on your system:

bundle exec rake bench

// License

AttrBool (https://github.com/esotericpig/attr_bool)
Copyright (c) 2020-2025 Bradley Whited
MIT License

About

πŸ”°πŸ±β“ Finally attr_accessor & attr_reader with question marks for booleans/predicates!?

Topics

Resources

License

Stars

Watchers

Forks

Languages