Easily create attr
(attribute) methods that end with question marks (?
).
require 'attr_bool'
module Wearable
extend AttrBool::Ext
attr_accessor? :in_fashion
attr_reader? :can_wash
end
class BananaHammock
extend AttrBool::Ext
include Wearable
# Enforce boolean (true or false) values.
attr_bool :princess
attr_bool? :crap_bag
end
banham = BananaHammock.new()
banham.in_fashion = true
banham.princess = true
p banham.in_fashion? #=> true
p banham.can_wash? #=> nil
p banham.princess? #=> true
p banham.crap_bag? #=> false
Require attr_bool/core_ext
to extend the core (monkey-patch) Module
& Class
(not recommended for libraries):
require 'attr_bool/core_ext'
class BananaHammock
attr_bool :princess
attr_bool? :crap_bag
end
// Similar Projects
Create an issue to add your project.
Gem Name | Code | Example |
---|---|---|
attr_asker | [GitHub] | attr_asker :running |
attr_boolean | [GitHub] | attr_boolean :running, default: true |
attr_setting | [GitHub] | attr_setting :running, true |
attribool | [GitHub] | bool_reader :name |
attribute_boolean | [GitHub] | attr_boolean :running |
boolean_accessor | [GitHub] | battr_accessor :running |
named_accessors | [GitHub] | named_reader :running, as: :running? |
property-accessor | [GitHub] | property(:running) { get(:running?); default { true } } |
question_mark_methods | [GitHub] | add_question_mark_methods running?: :running |
wannabe_bool | [GitHub] | attr_wannabe_bool :running |
wardrobe | [GitHub] | attribute :running, Wardrobe::Boolean, default: true |
Searches:
// Setup
Add attr_bool
to your Gemspec or Gemfile.
Or, use the RubyGems package manager:
$ gem install attr_bool
Or, manually:
$ git clone 'https://github.com/esotericpig/attr_bool.git'
$ cd attr_bool
$ bundle install
$ bundle exec rake install:local
// Usage
Either require attr_bool
or attr_bool/core_ext
.
The first one requires extending AttrBool::Ext
manually.
require 'attr_bool'
class Game
extend AttrBool::Ext
attr_accessor? :running
attr_reader? :winning
end
The second one automatically extends Module
& Class
, which is not recommended for sharing libraries.
require 'attr_bool/core_ext'
class Game
attr_accessor? :running
attr_reader? :winning
end
Now, simply use attr_accessor?
and/or attr_reader?
with one or more Symbols and/or Strings.
These do not force the values to be booleans (true or false).
For most purposes, this is adequate.
require 'attr_bool'
class Game
extend AttrBool::Ext
attr_accessor? :running,'looper'
attr_reader? :fps,'music'
def initialize()
@running = false
@looper = nil
@fps = 60
@music = 'Beatles'
end
end
game = Game.new()
puts game.running? #=> false
puts game.looper? #=> nil
puts game.fps? #=> 60
puts game.music? #=> 'Beatles'
game.running = true
game.looper = :main
puts game.running? #=> true
puts game.looper? #=> :main
There is also attr_writer?
, but it simply calls the standard attr_writer
unless you pass in a block.
To enforce boolean (true or false) values, use...
Name | Access |
---|---|
attr_bool or attr_boolor |
accessor |
attr_bool? |
reader |
attr_booler |
writer |
These are slightly slower due to always checking the values.
require 'attr_bool'
class Game
extend AttrBool::Ext
attr_bool :running,'looper'
attr_bool? :fps,'music'
attr_booler :sound
def initialize()
@fps = 60
@music = 'Beatles'
@sound = false
end
def loud?()
music? && @sound == true
end
end
game = Game.new()
puts game.running? #=> false
puts game.looper? #=> false
puts game.fps? #=> true
puts game.music? #=> true
puts game.loud? #=> false
game.running = true
game.looper = :main
game.sound = 'loud!'
puts game.running? #=> true
puts game.looper? #=> true
puts game.loud? #=> true
/// Default Values
A 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.
It'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.
If the last argument is not a Symbol
or a String
, then it will be used as the default value.
Note: attr_writer?
& attr_booler
can not take in a default value.
require 'attr_bool'
class Game
extend AttrBool::Ext
attr_accessor? :running,:looper,false
attr_reader? :min_fps,:max_fps,60
attr_bool :gravity,:wind,true
attr_bool? :min_force,:max_force,110
end
game = Game.new()
puts game.running? #=> false
puts game.looper? #=> false
puts game.min_fps? #=> 60
puts game.max_fps? #=> 60
puts game.gravity? #=> true
puts game.wind? #=> true
puts game.min_force? #=> true (not 110)
puts game.max_force? #=> true (not 110)
Instead 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
.
require 'attr_bool'
class Game
extend AttrBool::Ext
attr_accessor? :running,:looper,default: :main
attr_reader? :music,:sound,default: 'quiet!'
end
game = Game.new()
puts game.running? #=> :main
puts game.looper? #=> :main
puts game.music? #=> 'quiet!'
puts game.sound? #=> 'quiet!'
/// Block/Proc/Lambda
A 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.
With blocks, you can quickly write a dynamic attribute that depends on other variable(s) or tests variable(s) in some other special way.
Note: blocks do not update the instance variables; you must do this manually within the block. attr_accessor?/reader?/writer?
& attr_bool*
with blocks are exactly the same code (i.e., boolean values are not enforced).
require 'attr_bool'
class Game
extend AttrBool::Ext
attr_reader?(:lag) { print @ping,','; @ping > 300 }
attr_writer?(:ping) {|value| @ping = value.to_i() }
# Define 1 block for both reader & writer together.
attr_accessor?(:sound) do |value=nil|
if value.nil? # Assume reader
print @sound,','
@sound > 0
else # Assume writer
@sound = value.to_i() % 100
end
end
attr_bool?(:slow) { print @fps,','; @fps < 30 }
attr_booler(:fps) {|value| @fps = value.to_i() }
# Define separate blocks.
attr_bool(:music,
reader: -> { print @music,','; !@music.nil? },
writer: ->(value) { @music = value.to_sym() }
)
# Define only 1 block.
attr_accessor?(:frames,
reader: -> { @frames.odd? }
)
end
game = Game.new()
game.ping = 310.99
game.sound = 199.99
game.fps = 29.99
game.music = 'Beatles'
game.frames = 1
puts game.lag? #=> 310,true
puts game.sound? #=> 99,true
puts game.slow? #=> 29,true
puts game.music? #=> :Beatles,true
puts game.frames? #=> true
/// Complete Example
require 'attr_bool/core_ext'
module Wearable
# +attr_accessor?/reader?+ do not enforce boolean (true or false) values.
attr_accessor? :in_fashion,:in_season
attr_reader? :can_wash,:can_wear,default: 'yes!'
end
class BananaHammock
include Wearable
# +attr_bool*+ enforce boolean (true or false) values.
attr_bool :princess,:prince,default: 'Consuela'
attr_bool? :can_swim,:can_wink,true
attr_bool? (:crap_bag) { princess? && can_swim? }
attr_booler :friends
def for_friends()
@friends
end
end
banham = BananaHammock.new()
puts banham.in_fashion? #=> nil
puts banham.in_season? #=> nil
puts banham.can_wash? #=> 'yes!'
puts banham.can_wear? #=> 'yes!'
puts '---'
puts banham.princess? #=> true (not 'Consuela')
puts banham.prince? #=> true (not 'Consuela')
puts banham.can_swim? #=> true
puts banham.can_wink? #=> true
puts banham.crap_bag? #=> true
puts '---'
banham.in_fashion = true
banham.in_season = 'always'
banham.princess = nil
banham.prince = 'Charming'
banham.friends = 'Valerie'
puts banham.in_fashion? #=> true
puts banham.in_season? #=> 'always'
puts banham.princess? #=> false (not nil)
puts banham.prince? #=> true (not 'Charming')
puts banham.crap_bag? #=> false (dynamic; because +princess?+ is now false)
puts banham.for_friends #=> true (not 'Valerie')
/// YARDoc
A custom AttributeHandler
plugin is planned for the next version:
For now, please use one of YARDoc's built-in ways:
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
# @!method can_wear?
# @return [true,false] whether it's wearable (default: +true+)
attr_reader? :can_wear,true
# @!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
$ bundle exec rake test
$ bundle exec rake doc
$ bundle exec rake install:local
$ bundle exec rake release
/// Benchmarks
There are some benchmarks that test define_method
vs module_eval
and ? true : false
vs !!
.
To run these on your system:
$ bundle exec rake benchmark
// License
AttrBool (https://github.com/esotericpig/attr_bool)
Copyright (c) 2020-2021 Jonathan Bradley WhitedPermission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.