kind 0.1.0 → 0.2.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: 82342a2c0b637164a1eb73c8a47d3f2040225d04e8bfa28d1334e46a0a7afc9f
4
- data.tar.gz: 6672a142b2692618e3486ca7a039ba6d80915d19d01995c355a7af337bff6416
3
+ metadata.gz: 9b572e02668d3a89864333fad8605a280f3bb09f5de9c0db9800bdc956632b78
4
+ data.tar.gz: 643847caaa8791c0bb5f4304f9e14135e853fb9763c53f92d7c3760c5d384be5
5
5
  SHA512:
6
- metadata.gz: 2127164f8a852f3791460a6fbd944d05c2f023e4676351a25194b69679bd1e9c8e6c40a66a44d6ea5db37429d5a4be2ce48677b2671c6570859cfc4224aa05b9
7
- data.tar.gz: 119bc6bfd8a7ce9cb0fc839da075456555adc12ddf49ed5d725bd11ca6c1f0ed9e69e134941c2c90d79d71c4bf7929cc4dd9b02072720fe261f227b6554f54f0
6
+ metadata.gz: c8d9057024bb9c8dd10f69946e5fcf0027f07a848dd16772bcb81dd2d9eeff12f026fe3600808c24bcf60126274d27a170ee32ab37f73f7fdaa26377e2aa1704
7
+ data.tar.gz: d4872142369aadb04b2679bc1bf8bb6b690ea19b9a7208dc9b0cb3f25c32f275981479d7847e0fe884bbb3c43c1da748c40ecd47e8833ff4052848514f3fcf1c
data/.gitignore CHANGED
@@ -6,3 +6,6 @@
6
6
  /pkg/
7
7
  /spec/reports/
8
8
  /tmp/
9
+
10
+ Gemfile.lock
11
+ .foo
data/README.md CHANGED
@@ -1,8 +1,27 @@
1
+ - [Kind](#kind)
2
+ - [Installation](#installation)
3
+ - [Usage](#usage)
4
+ - [Verifying the kind of some object](#verifying-the-kind-of-some-object)
5
+ - [Verifying the kind of some class/module](#verifying-the-kind-of-some-classmodule)
6
+ - [Built-in type checkers](#built-in-type-checkers)
7
+ - [Special type checkers](#special-type-checkers)
8
+ - [Kind.of](#kindof)
9
+ - [Kind.is](#kindis)
10
+ - [How to create a new type checker?](#how-to-create-a-new-type-checker)
11
+ - [Development](#development)
12
+ - [Contributing](#contributing)
13
+ - [License](#license)
14
+ - [Code of Conduct](#code-of-conduct)
15
+
1
16
  # Kind
2
17
 
3
- Welcome to your new gem! In this directory, you'll find the files you need to be able to package up your Ruby library into a gem. Put your Ruby code in the file `lib/kind`. To experiment with that code, run `bin/console` for an interactive prompt.
18
+ Basic type system for Ruby.
19
+
20
+ **Motivation:**
4
21
 
5
- TODO: Delete this and the text above, and describe your gem
22
+ As a creator of Ruby gems, I have a common need that I have to handle in many of my projects: type checking of method arguments.
23
+
24
+ One of the goals of this project is to do simple type checking like `"some string".is_a?(String)`, but using a bunch of basic abstractions. So, after reading this README and realizing that you need something more robust, I recommend to you check out the [dry-types gem](https://dry-rb.org/gems/dry-types).
6
25
 
7
26
  ## Installation
8
27
 
@@ -22,7 +41,155 @@ Or install it yourself as:
22
41
 
23
42
  ## Usage
24
43
 
25
- TODO: Write usage instructions here
44
+ ### Verifying the kind of some object
45
+
46
+ By default, basic type verification is strict. So, when you perform `Kind.of.Hash(value)`, if the given value was a Hash it will be returned, but if it wasn't one, an error will be raised.
47
+
48
+ ```ruby
49
+ Kind.of.Hash('')
50
+ # raise Kind::Error, "'' expected to be a kind of Hash"
51
+
52
+ Kind.of.Hash({a: 1})
53
+ # {a: 1}
54
+
55
+ # ---
56
+
57
+ Kind.of.Boolean(nil)
58
+ # raise Kind::Error, "nil expected to be a kind of Boolean"
59
+
60
+ Kind.of.Boolean(true) # true
61
+ Kind.of.Boolean(false) # false
62
+ ```
63
+
64
+ As an alternative syntax, you can use the `Kind::Of` instead of the method. e.g: `Kind::Of::Hash('')`
65
+
66
+ But if you don't need a strict type verification, use the `.or_nil`method
67
+
68
+ ```ruby
69
+ Kind.of.Hash.or_nil('')
70
+ # nil
71
+
72
+ Kind.of.Hash.or_nil({a: 1})
73
+ # {a: 1}
74
+
75
+ # ---
76
+
77
+ Kind.of.Boolean.or_nil('') # nil
78
+ Kind.of.Boolean.or_nil(true) # true
79
+ ```
80
+
81
+ And just for convenience, you can use the method `.instance?` to verify if the given object has the expected type.
82
+
83
+ ```ruby
84
+ Kind.of.Hash.instance?('')
85
+ # false
86
+
87
+ # ---
88
+
89
+ Kind.of.Boolean.instance?('') # false
90
+ Kind.of.Boolean.instance?(true) # true
91
+ Kind.of.Boolean.instance?(false) # true
92
+ ```
93
+
94
+ ### Verifying the kind of some class/module
95
+
96
+ You can use `Kind.is` to verify if some class has the expected type as its ancestor.
97
+
98
+ ```ruby
99
+ Kind.is.Hash(String)
100
+ # false
101
+
102
+ Kind.is.Hash(Hash)
103
+ # true
104
+
105
+ Kind.is.Hash(ActiveSupport::HashWithIndifferentAccess)
106
+ # true
107
+ ```
108
+
109
+ And just for convenience, you can use the method `Kind.of.*.class?` to verify if the given class has the expected type as its ancestor.
110
+
111
+ ```ruby
112
+ Kind.of.Hash.class?(Hash)
113
+ # true
114
+
115
+ Kind.of.Hash.class?(ActiveSupport::HashWithIndifferentAccess)
116
+ ```
117
+
118
+ ## Built-in type checkers
119
+
120
+ The list of types (classes and modules) available to use with `Kind.of.*` or `Kind.is.*` are:
121
+
122
+ | Classes | Modules |
123
+ | ---------- | ---------- |
124
+ | String | Enumerable |
125
+ | Symbol | Comparable |
126
+ | Numeric | |
127
+ | Integer | |
128
+ | Float | |
129
+ | Regexp | |
130
+ | Time | |
131
+ | Array | |
132
+ | Range | |
133
+ | Hash | |
134
+ | Struct | |
135
+ | Enumerator | |
136
+ | Method | |
137
+ | Proc | |
138
+ | IO | |
139
+ | File | |
140
+
141
+ ### Special type checkers
142
+
143
+ #### Kind.of
144
+
145
+ - `Kind.of.Class()`
146
+ - `Kind.of.Module()`
147
+ - `Kind.of.Lambda()`
148
+ - `Kind.of.Boolean()`
149
+
150
+ #### Kind.is
151
+
152
+ - `Kind.of.Class()`
153
+ - `Kind.of.Module()`
154
+ - `Kind.of.Boolean()`
155
+
156
+ ## How to create a new type checker?
157
+
158
+ Use `Kind::Types.add()`. e.g:
159
+
160
+ ```ruby
161
+ class User
162
+ end
163
+
164
+ # You can define it at the end of the file which has the class/module.
165
+
166
+ Kind::Types.add(User)
167
+
168
+ # Or, you can add the type checker within the class definition.
169
+
170
+ class User
171
+ Kind::Types.add(self)
172
+ end
173
+
174
+ # --------------- #
175
+ # Usage examples: #
176
+ # --------------- #
177
+
178
+ Kind.of.User(User.new)
179
+ # #<User:0x0000...>
180
+
181
+ Kind.of.User({})
182
+ # Kind::Error ({} expected to be a kind of User)
183
+
184
+ Kind.of.User.or_nil({})
185
+ # nil
186
+
187
+ Kind.of.User.instance?({}) # false
188
+ Kind.of.User.class?(Hash) # false
189
+
190
+ Kind.of.User.instance?(User) # true
191
+ Kind.of.User.class?(User) # true
192
+ ```
26
193
 
27
194
  ## Development
28
195
 
@@ -32,7 +199,7 @@ To install this gem onto your local machine, run `bundle exec rake install`. To
32
199
 
33
200
  ## Contributing
34
201
 
35
- Bug reports and pull requests are welcome on GitHub at https://github.com/[USERNAME]/kind. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the [code of conduct](https://github.com/[USERNAME]/kind/blob/master/CODE_OF_CONDUCT.md).
202
+ Bug reports and pull requests are welcome on GitHub at https://github.com/serradura/kind. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the [code of conduct](https://github.com/serradura/kind/blob/master/CODE_OF_CONDUCT.md).
36
203
 
37
204
 
38
205
  ## License
@@ -41,4 +208,4 @@ The gem is available as open source under the terms of the [MIT License](https:/
41
208
 
42
209
  ## Code of Conduct
43
210
 
44
- Everyone interacting in the Kind project's codebases, issue trackers, chat rooms and mailing lists is expected to follow the [code of conduct](https://github.com/[USERNAME]/kind/blob/master/CODE_OF_CONDUCT.md).
211
+ Everyone interacting in the Kind project's codebases, issue trackers, chat rooms and mailing lists is expected to follow the [code of conduct](https://github.com/serradura/kind/blob/master/CODE_OF_CONDUCT.md).
@@ -5,7 +5,7 @@ require 'kind/version'
5
5
  module Kind
6
6
  class Error < TypeError
7
7
  def initialize(klass, object)
8
- super("#{object} expected to be a kind of #{klass}")
8
+ super("#{object.inspect} expected to be a kind of #{klass}")
9
9
  end
10
10
  end
11
11
 
@@ -19,25 +19,86 @@ module Kind
19
19
  def self.Class(object)
20
20
  self.call(::Class, object)
21
21
  end
22
+
23
+ def self.Module(object)
24
+ self.call(::Module, object)
25
+ end
26
+
27
+ def self.Boolean(object = nil)
28
+ return Kind::Of::Boolean if object.nil?
29
+
30
+ return object if object.is_a?(::TrueClass) || object.is_a?(::FalseClass)
31
+
32
+ raise Kind::Error.new('Boolean'.freeze, object)
33
+ end
34
+
35
+ module Boolean
36
+ def self.class?(value)
37
+ Kind.is.Boolean(value)
38
+ end
39
+
40
+ def self.instance?(value)
41
+ value.is_a?(TrueClass) || value.is_a?(FalseClass)
42
+ end
43
+
44
+ def self.or_nil(value)
45
+ return value if instance?(value)
46
+ end
47
+ end
48
+
49
+ def self.Lambda(object = nil)
50
+ return Kind::Of::Lambda if object.nil?
51
+
52
+ return object if object.is_a?(::Proc) && object.lambda?
53
+
54
+ raise Kind::Error.new('Lambda'.freeze, object)
55
+ end
56
+
57
+ module Lambda
58
+ def self.class?(value)
59
+ Kind.is.Proc(value)
60
+ end
61
+
62
+ def self.instance?(value)
63
+ value.is_a?(::Proc) && value.lambda?
64
+ end
65
+
66
+ def self.or_nil(value)
67
+ return value if instance?(value)
68
+ end
69
+ end
22
70
  end
23
71
 
24
72
  module Is
25
73
  def self.call(expected, value)
26
- expected_klass, klass = Kind.of.Class(expected), Kind.of.Class(value)
74
+ expected_klass, klass = Kind.of.Module(expected), Kind.of.Module(value)
75
+
76
+ klass <= expected_klass || false
77
+ end
78
+
79
+ def self.Class(value)
80
+ value.is_a?(::Class)
81
+ end
82
+
83
+ def self.Module(value)
84
+ value == Module || (value.is_a?(::Module) && !self.Class(value))
85
+ end
27
86
 
28
- klass <= expected_klass
87
+ def self.Boolean(value)
88
+ klass = Kind.of.Class(value)
89
+ klass <= TrueClass || klass <= FalseClass
29
90
  end
30
91
  end
31
92
 
32
93
  def self.of; Of; end
33
94
  def self.is; Is; end
34
95
 
35
- singleton_class.send(:alias_method, :is_a, :is)
36
-
37
96
  module Types
97
+ extend self
98
+
38
99
  KIND_OF = <<-RUBY
39
100
  def self.%{klass}(object = nil)
40
- return Kind::Of::%{klass} unless object
101
+ return Kind::Of::%{klass} if object.nil?
41
102
 
42
103
  Kind::Of.call(::%{klass}, object)
43
104
  end
@@ -65,8 +126,8 @@ module Kind
65
126
 
66
127
  private_constant :KIND_OF, :KIND_IS, :KIND_OF_MODULE
67
128
 
68
- def self.add(klass)
69
- klass_name = Kind.of.Class(klass).name
129
+ def add(klass)
130
+ klass_name = Kind.of.Module(klass).name
70
131
 
71
132
  return if Of.respond_to?(klass_name)
72
133
 
@@ -83,6 +144,16 @@ module Kind
83
144
  end
84
145
  end
85
146
 
86
- [Hash, String]
87
- .each { |klass| Types.add(klass) }
147
+ # Classes
148
+ [
149
+ String, Symbol, Numeric, Integer, Float, Regexp, Time,
150
+ Array, Range, Hash, Struct, Enumerator,
151
+ Method, Proc,
152
+ IO, File
153
+ ].each { |klass| Types.add(klass) }
154
+
155
+ # Modules
156
+ [
157
+ Enumerable, Comparable
158
+ ].each { |klass| Types.add(klass) }
88
159
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Kind
4
- VERSION = '0.1.0'
4
+ VERSION = '0.2.0'
5
5
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: kind
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 0.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Rodrigo Serradura
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2019-12-26 00:00:00.000000000 Z
11
+ date: 2020-01-02 00:00:00.000000000 Z
12
12
  dependencies: []
13
13
  description: Basic type system for Ruby.
14
14
  email:
@@ -21,7 +21,6 @@ files:
21
21
  - ".travis.yml"
22
22
  - CODE_OF_CONDUCT.md
23
23
  - Gemfile
24
- - Gemfile.lock
25
24
  - LICENSE.txt
26
25
  - README.md
27
26
  - Rakefile
@@ -1,21 +0,0 @@
1
- PATH
2
- remote: .
3
- specs:
4
- kind (0.1.0)
5
-
6
- GEM
7
- remote: https://rubygems.org/
8
- specs:
9
- minitest (5.13.0)
10
- rake (12.3.2)
11
-
12
- PLATFORMS
13
- ruby
14
-
15
- DEPENDENCIES
16
- kind!
17
- minitest (~> 5.0)
18
- rake (~> 12.0)
19
-
20
- BUNDLED WITH
21
- 2.1.2