kind 0.1.0 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
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