attribool 0.0.1 → 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 469b94667c5be65a2901c9049f8290711c823fc7d08226140471c4c8820e66df
4
- data.tar.gz: 526c90658fc7f1ac712383083a5c38ced3088f3ed91fc32af3a6801e7c0352cc
3
+ metadata.gz: dc735929535da353af1b584656aafb3ba6ba46b7996af32ae37dedc30bcfb0a2
4
+ data.tar.gz: 116a6a7fd8f9803773d10a6fff0b294f73bb9f5eb872db573f11273f8fc1ddcb
5
5
  SHA512:
6
- metadata.gz: 90be0ebf1c939bf765d0dd3848cf273b00606d4e00335418b1fc44de239ffb5f2042032525a22f9b205b9b10b6ff71126ba0a3c01449d2957fe328f4be354359
7
- data.tar.gz: 48dbb1b70a57413523a962d29432343e5c7117f06ceae8063a7de1a5306595bab5f469db638a25bed1074efee037982e4a776c75334168e9d6e0064359e9e240
6
+ metadata.gz: 73fc2ab7f625fdfbb7577cda39c60eb86f6f53511fa685b2c0b86a79c90d22876123fcd34db74a76deb25eabc223cf891964fac36f962732af87a0c0c9aabcb0
7
+ data.tar.gz: ec6dc2496637c4c21c3c252a4c02fa1d574b4e4e033b74bd9019d5a8c286febba0990cd6d5659cc15be20b6a6c6dc3428f23a8bcb11ded8ed6a884403f78f682
@@ -0,0 +1,35 @@
1
+ # This workflow uses actions that are not certified by GitHub.
2
+ # They are provided by a third-party and are governed by
3
+ # separate terms of service, privacy policy, and support
4
+ # documentation.
5
+ # This workflow will download a prebuilt Ruby version, install dependencies and run tests with Rake
6
+ # For more information see: https://github.com/marketplace/actions/setup-ruby-jruby-and-truffleruby
7
+
8
+ name: Ruby
9
+
10
+ on:
11
+ push:
12
+ branches: [ master ]
13
+ pull_request:
14
+ branches: [ master ]
15
+
16
+ jobs:
17
+ test:
18
+
19
+ runs-on: ubuntu-latest
20
+ strategy:
21
+ matrix:
22
+ ruby-version: ['2.6', '2.7', '3.0']
23
+
24
+ steps:
25
+ - uses: actions/checkout@v2
26
+ - name: Set up Ruby
27
+ # To automatically get bug fixes and new Ruby versions for ruby/setup-ruby,
28
+ # change this to (see https://github.com/ruby/setup-ruby#versioning):
29
+ # uses: ruby/setup-ruby@v1
30
+ uses: ruby/setup-ruby@473e4d8fe5dd94ee328fdfca9f8c9c7afc9dae5e
31
+ with:
32
+ ruby-version: ${{ matrix.ruby-version }}
33
+ bundler-cache: true # runs 'bundle install' and caches installed gems automatically
34
+ - name: Run tests
35
+ run: bundle exec rake
data/.gitignore CHANGED
@@ -1,2 +1,3 @@
1
1
  attribool-*.gem
2
2
  coverage/*
3
+ docs/*
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- attribool (0.0.1)
4
+ attribool (1.0.0)
5
5
 
6
6
  GEM
7
7
  remote: https://rubygems.org/
@@ -28,4 +28,4 @@ DEPENDENCIES
28
28
  test-unit (~> 3.3, >= 3.3.5)
29
29
 
30
30
  BUNDLED WITH
31
- 2.1.4
31
+ 2.2.17
data/README.md CHANGED
@@ -1,22 +1,34 @@
1
1
  # Attribool
2
+ [![Build Status](https://img.shields.io/endpoint.svg?url=https%3A%2F%2Factions-badge.atrox.dev%2Fevanthegrayt%2Fattribool%2Fbadge%3Fref%3Dmaster&style=flat)](https://actions-badge.atrox.dev/evanthegrayt/attribool/goto?ref=master)
3
+ [![Gem Version](https://badge.fury.io/rb/attribool.svg)](https://badge.fury.io/rb/attribool)
4
+ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
5
+
2
6
  Ruby macros for creating boolean methods for attributes that may or may not be
3
- booleans themselves. This is done via coercion based on truthiness. For example,
4
- if you have an attribute of `@name`, and you want to know if `@name` is not
5
- `nil`, you can declare `bool_reader :name`, which will define the method
6
- `name?`. This method will return true if `@name` is truthy.
7
+ booleans themselves. This is done via either coercion based on truthiness, or a
8
+ user-defined condition.
9
+
10
+ For example, if you have an attribute of `@name`, and you want to know if
11
+ `@name` is not `nil`, you can declare `bool_reader :name`, which will define the
12
+ method `name?`. This method will return true if `@name` is truthy.
7
13
 
8
14
  The `bool_reader` also comes with some handy options. For example, you can
9
- [define a method name](#a-bool_reader-with-method-name-or-prefix) that makes
10
- more sense. Using the same example, as above, if your attribute is `@name`, but
15
+ [define a method name](#a-bool_reader-with-method-name) that makes
16
+ more sense. Using the same example as above, if your attribute is `@name`, but
11
17
  you'd like for your boolean method to be called `named?`, you can use
12
- `bool_reader :name, method: :named?`.
18
+ `bool_reader :name, method_name: :named?`.
13
19
  [Conditionals](#a-bool_reader-with-method-name-and-conditional) can also be set
14
20
  with lambdas via the `condition:` keyword argument.
15
21
 
22
+ The first argument is always the instance variable to check for truthiness.
23
+ Because of this, it is also valid syntax to use `bool_reader :@name`, if it
24
+ makes more sense to you.
25
+
16
26
  Macros also exist for `bool_writer` and `bool_accessor`. When a writer
17
27
  method is defined, the value will always be coerced into a boolean before
18
28
  setting the attribute.
19
29
 
30
+ You can read the documentation [here](https://evanthegrayt.github.io/attribool/).
31
+
20
32
  ## Installation
21
33
  #### Via Gemfile
22
34
  ```ruby
@@ -45,6 +57,10 @@ class Person
45
57
 
46
58
  attr_accessor :name
47
59
  bool_reader :name
60
+ # OR
61
+ # bool_reader :@name
62
+ # bool_reader 'name'
63
+ # bool_reader '@name'
48
64
  end
49
65
 
50
66
  person = Person.new
@@ -58,7 +74,7 @@ person.name?
58
74
  # true, because @name is truthy.
59
75
  ```
60
76
 
61
- #### A bool_reader with method name or prefix
77
+ #### A bool_reader with method name
62
78
  ```ruby
63
79
  require 'attribool'
64
80
 
@@ -66,18 +82,15 @@ class Person
66
82
  extend Attribool
67
83
 
68
84
  attr_accessor :name
69
- bool_reader :name, method: :named?
70
- bool_reader :name, prefix: :has?
85
+ bool_reader :name, method_name: :named?
71
86
  end
72
87
 
73
88
  person = Person.new
74
89
  person.named?
75
- person.has_name?
76
90
  # false, because @name is nil.
77
91
 
78
92
  person.name = 'John Smith'
79
93
  person.named?
80
- person.has_name?
81
94
  # true, because @name is truthy.
82
95
  ```
83
96
 
@@ -90,7 +103,7 @@ class Person
90
103
 
91
104
  attr_accessor :age
92
105
  # In the condition lambdas, the argument refers to the attribute's value.
93
- bool_reader :age, method: :adult?, condition: ->(a) { a.to_i >= 18 }
106
+ bool_reader :age, method_name: :adult?, condition: ->(a) { a.to_i >= 18 }
94
107
  end
95
108
 
96
109
  person = Person.new
@@ -106,6 +119,34 @@ person.adult?
106
119
  # true, because @age is greater than 18.
107
120
  ```
108
121
 
122
+ #### Assigning more than one bool_reader with a method name at once
123
+ ```ruby
124
+ require 'attribool'
125
+
126
+ class Person
127
+ extend Attribool
128
+
129
+ attr_accessor :name, :age
130
+ # When creating multiple readers at once, if you want to specify a
131
+ # method_name, you must provide a Proc as the argument, where the attribute
132
+ # name is the argument.
133
+ bool_reader :age, :name, method_name: ->(m) { "has_#{m}?" }
134
+ end
135
+
136
+ person = Person.new
137
+ person.has_age?
138
+ person.has_name?
139
+ # Both false, because @age and @name are nil.
140
+
141
+ person.age = 10
142
+ person.has_age?
143
+ # true, because @age is not nil.
144
+
145
+ person.name = 'Bob'
146
+ person.has_name?
147
+ # true, because @name is not nil.
148
+ ```
149
+
109
150
  #### Standard bool_accessor
110
151
  ```ruby
111
152
  require 'attribool'
@@ -123,5 +164,40 @@ person.living?
123
164
  person.living = true
124
165
  person.living?
125
166
  # true, because @living is true.
126
- # Be aware -- if you pass a string, it will be coerced to true!
167
+ # Be aware -- if you pass anything truthy, it will be coerced to true!
127
168
  ```
169
+
170
+ #### Standard bool_writer
171
+ In most cases where you'd use a `bool_writer`, you'd probably want to just use
172
+ `bool_accessor`. This example is to show that, even when using `bool_accessor`,
173
+ the value is coerced to a boolean when the value is set by `bool_writer`.
174
+ ```ruby
175
+ require 'attribool'
176
+
177
+ class Person
178
+ extend Attribool
179
+
180
+ attr_reader :living
181
+ bool_writer :living
182
+ end
183
+
184
+ person = Person.new
185
+ person.living
186
+ # nil
187
+
188
+ person.living = 'blah'
189
+ person.living
190
+ # true, because 'blah' was coerced into a boolean because strings are truthy.
191
+ ```
192
+
193
+ ## Reporting Bugs and Requesting Features
194
+ If you have an idea or find a bug, please [create an
195
+ issue](https://github.com/evanthegrayt/attribool/issues/new). Just make sure
196
+ the topic doesn't already exist. Better yet, you can always submit a Pull
197
+ Request.
198
+
199
+ ## Self-Promotion
200
+ I do these projects for fun, and I enjoy knowing that they're helpful to people.
201
+ Consider starring [the repository](https://github.com/evanthegrayt/attribool)
202
+ if you like it! If you love it, follow me [on
203
+ GitHub](https://github.com/evanthegrayt)!
data/Rakefile CHANGED
@@ -14,7 +14,7 @@ end
14
14
 
15
15
  RDoc::Task.new do |rdoc|
16
16
  rdoc.main = 'README.md'
17
- rdoc.rdoc_dir = 'doc'
17
+ rdoc.rdoc_dir = 'docs'
18
18
  rdoc.rdoc_files.include('README.md', 'lib/**/*.rb')
19
19
  end
20
20
 
data/attribool.gemspec CHANGED
@@ -2,7 +2,7 @@ require_relative 'lib/attribool/version'
2
2
 
3
3
  Gem::Specification.new do |spec|
4
4
  spec.name = 'attribool'
5
- spec.version = Attribool::Version.to_s
5
+ spec.version = Attribool::VERSION
6
6
  spec.authors = ['Evan Gray']
7
7
  spec.email = 'evanthegrayt@vivaldi.net'
8
8
  spec.license = 'MIT'
@@ -19,10 +19,8 @@ Gem::Specification.new do |spec|
19
19
 
20
20
  spec.metadata['allowed_push_host'] = 'https://rubygems.org'
21
21
  spec.metadata['homepage_uri'] = spec.homepage
22
- spec.metadata['source_code_uri'] =
23
- 'https://github.com/evanthegrayt/attribool'
24
- spec.metadata['documentation_uri'] =
25
- 'https://evanthegrayt.github.io/attribool/doc/index.html'
22
+ spec.metadata['source_code_uri'] = 'https://github.com/evanthegrayt/attribool'
23
+ spec.metadata['documentation_uri'] = 'https://evanthegrayt.github.io/attribool/'
26
24
 
27
25
  spec.files = `git ls-files -z`.split("\x0").reject do |f|
28
26
  f.match(%r{^(test|spec|features)/})
@@ -0,0 +1,10 @@
1
+ class Attribool::Attribute
2
+ attr_reader :name
3
+ attr_reader :ivar
4
+
5
+ def initialize(attribute)
6
+ attribute = attribute.to_s
7
+ @ivar = attribute.start_with?('@') ? attribute : "@#{attribute}"
8
+ @name = @ivar.delete_prefix('@')
9
+ end
10
+ end
@@ -0,0 +1,18 @@
1
+ class Attribool::MethodName
2
+ attr_reader :name
3
+
4
+ def self.validate(method_name, number_of_attributes)
5
+ if number_of_attributes > 1 && method_name && !method_name.is_a?(Proc)
6
+ raise ArgumentError, "Must use a Proc when creating multiple methods"
7
+ end
8
+ end
9
+
10
+ def initialize(attribute, method_name)
11
+ @name =
12
+ case method_name
13
+ when Proc then method_name.call(attribute)
14
+ when nil then "#{attribute}?"
15
+ else method_name
16
+ end
17
+ end
18
+ end
@@ -9,7 +9,7 @@ module Attribool
9
9
  # Major version.
10
10
  #
11
11
  # @return [Integer]
12
- MAJOR = 0
12
+ MAJOR = 1
13
13
 
14
14
  ##
15
15
  # Minor version.
@@ -21,14 +21,32 @@ module Attribool
21
21
  # Patch version.
22
22
  #
23
23
  # @return [Integer]
24
- PATCH = 1
24
+ PATCH = 0
25
+
26
+ ##
27
+ # Version as +[MAJOR, MINOR, PATCH]+
28
+ #
29
+ # @return [Array]
30
+ def self.to_a
31
+ [MAJOR, MINOR, PATCH]
32
+ end
25
33
 
26
34
  ##
27
35
  # Version as +MAJOR.MINOR.PATCH+
28
36
  #
29
37
  # @return [String]
30
38
  def self.to_s
31
- "#{MAJOR}.#{MINOR}.#{PATCH}"
39
+ to_a.join('.')
40
+ end
41
+
42
+ ##
43
+ # Version as +{major: MAJOR, minor: MINOR, patch: PATCH}+
44
+ #
45
+ # @return [Hash]
46
+ def self.to_h
47
+ %i[major minor patch].zip(to_a).to_h
32
48
  end
33
49
  end
50
+
51
+ VERSION = Version.to_s.freeze
34
52
  end
data/lib/attribool.rb CHANGED
@@ -1,96 +1,66 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require_relative 'attribool/version'
4
+ require_relative 'attribool/method_name'
5
+ require_relative 'attribool/attribute'
6
+
3
7
  ##
4
- # Adds macros and methods for dealing with boolean attributes.
8
+ # Adds macros for dealing with boolean attributes.
5
9
  module Attribool
6
- def self.included(klass)
7
- klass.extend(ClassMethods)
8
- end
9
-
10
10
  ##
11
- # Class methods to be added to the class when included.
12
- module ClassMethods
13
- ##
14
- # Creates a method that returns a boolean for attributes that may or may
15
- # not be booleans themselves.
16
- #
17
- # @param [Symbol, String] attribute
18
- #
19
- # @kwarg [Boolean] allow_nil:
20
- #
21
- # @kwarg [Lambda] condition:
22
- #
23
- # @kwarg [Symbol, String] method:
24
- #
25
- # @kwarg [Symbol, String] prefix:
26
- def bool_reader(
27
- attribute,
28
- allow_nil: true,
29
- condition: nil,
30
- prefix: nil,
31
- method: nil
32
- )
33
- method ||= "#{attribute}?"
34
- method = "#{prefix}_#{method}" if prefix
35
- define_method(method) do
36
- ivar = instance_variable_get("@#{attribute}")
37
- raise TypeError, "#{attribute} is nil" if ivar.nil? && !allow_nil
38
-
39
- condition ? condition.call(ivar) : to_boolean(ivar)
40
- end
41
- end
42
-
43
- ##
44
- # Creates a writer for boolean attributes. Always coerces to boolean based
45
- # on truthiness.
46
- #
47
- # @param [Symbol, String] attribute
48
- #
49
- # @kwarg [Boolean] strict:
50
- def bool_writer(attribute, strict: false)
51
- define_method("#{attribute}=") do |v|
52
- validate_boolean(v) if strict
11
+ # Creates methods that return a boolean for attributes that may or may not be
12
+ # booleans themselves. Multiple readers can be created at once
13
+ #
14
+ # @param [Symbol, String] *attributes
15
+ #
16
+ # @kwarg [Boolean] allow_nil
17
+ #
18
+ # @kwarg [Proc] condition
19
+ #
20
+ # @kwarg [Symbol, String, Proc] method_name
21
+ def bool_reader(
22
+ *attributes,
23
+ allow_nil: true,
24
+ condition: nil,
25
+ method_name: nil
26
+ )
27
+ MethodName.validate(method_name, attributes.size)
28
+ attributes.map { |a| Attribute.new(a) }.each do |attribute|
29
+ define_method(MethodName.new(attribute.name, method_name).name) do
30
+ value = instance_variable_get(attribute.ivar)
31
+ raise TypeError, "#{attribute.ivar} is nil" if value.nil? && !allow_nil
53
32
 
54
- instance_variable_set("@#{attribute}", to_boolean(v))
33
+ condition ? condition.call(value) : !!(value)
55
34
  end
56
35
  end
57
-
58
- ##
59
- # Creates a simple reader and writer for booleans. This should only be used
60
- # when the attribute should only ever be +true+ or +false+.
61
- #
62
- # @param [Symbol, String] attribute
63
- def bool_accessor(attribute)
64
- bool_reader(attribute)
65
- bool_writer(attribute)
66
- end
67
36
  end
68
37
 
69
38
  ##
70
- # Is the argument a boolean?
39
+ # Creates a writer for boolean attributes. Always coerces to boolean based
40
+ # on truthiness.
71
41
  #
72
- # @param [Object] attribute
42
+ # @param [Symbol, String] *attributes
73
43
  #
74
- # @return [Boolean]
75
- def boolean?(attribute)
76
- [TrueClass, FalseClass].include?(attribute.class)
77
- end
44
+ # @kwarg [Boolean] strict
45
+ def bool_writer(*attributes, strict: false)
46
+ attributes.map { |a| Attribute.new(a) }.each do |attribute|
47
+ define_method("#{attribute.name}=") do |v|
48
+ if strict && ![TrueClass, FalseClass].include?(v.class)
49
+ raise ArgumentError, 'Argument must be a boolean'
50
+ end
78
51
 
79
- ##
80
- # Converts an Object to a boolean.
81
- #
82
- # @param [Object] attribute
83
- #
84
- # @return [Boolean]
85
- def to_boolean(attribute)
86
- !!attribute
52
+ instance_variable_set(attribute.ivar, !!v)
53
+ end
54
+ end
87
55
  end
88
56
 
89
- private
90
-
91
57
  ##
92
- # Raises if argument is not a boolean.
93
- def validate_boolean(attribute) # :nodoc:
94
- raise ArgumentError, 'Argument must be a boolean' unless boolean?(attribute)
58
+ # Creates a simple reader and writer for booleans. This should only be used
59
+ # when the attribute should only ever be +true+ or +false+.
60
+ #
61
+ # @param [Symbol, String] *attributes
62
+ def bool_accessor(*attributes)
63
+ bool_reader(*attributes)
64
+ bool_writer(*attributes)
95
65
  end
96
66
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: attribool
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.1
4
+ version: 1.0.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Evan Gray
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2021-04-22 00:00:00.000000000 Z
11
+ date: 2022-01-06 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rake
@@ -70,6 +70,7 @@ executables: []
70
70
  extensions: []
71
71
  extra_rdoc_files: []
72
72
  files:
73
+ - ".github/workflows/ruby.yml"
73
74
  - ".gitignore"
74
75
  - Gemfile
75
76
  - Gemfile.lock
@@ -78,6 +79,8 @@ files:
78
79
  - Rakefile
79
80
  - attribool.gemspec
80
81
  - lib/attribool.rb
82
+ - lib/attribool/attribute.rb
83
+ - lib/attribool/method_name.rb
81
84
  - lib/attribool/version.rb
82
85
  homepage: https://github.com/evanthegrayt/attribool
83
86
  licenses:
@@ -86,7 +89,7 @@ metadata:
86
89
  allowed_push_host: https://rubygems.org
87
90
  homepage_uri: https://github.com/evanthegrayt/attribool
88
91
  source_code_uri: https://github.com/evanthegrayt/attribool
89
- documentation_uri: https://evanthegrayt.github.io/attribool/doc/index.html
92
+ documentation_uri: https://evanthegrayt.github.io/attribool/
90
93
  post_install_message:
91
94
  rdoc_options: []
92
95
  require_paths: