taipo 1.0.0 → 1.0.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +74 -30
- data/lib/taipo/parser/validater.rb +91 -2
- data/lib/taipo/type_element/constraint.rb +1 -1
- data/lib/taipo/version.rb +1 -1
- data/lib/taipo.rb +19 -3
- data/taipo.gemspec +2 -0
- metadata +5 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 5583e28b7b31de0e646bbdf2f03f274417946935
|
4
|
+
data.tar.gz: 5b9d14b293cabde611addc66b7857c2a16a46929
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: b9c8e5d7fc2d9a419fb91cb82d063e2c4e294ba5b43677546557a133b9e0dbae420c3984f499381ae4e4d54157eb254fa0106720e6e44c2b271bacb34a97e487
|
7
|
+
data.tar.gz: 84aee96a5489147d14e7d2ed37ae66dbbbf8f7a6d9e12a365c4fb901160e91d6a58f6bbd6e5d59d03bbe3183b07030215fb5f0c5f74b644f28b88dbcddc3c885
|
data/README.md
CHANGED
@@ -1,7 +1,13 @@
|
|
1
|
+
[![Gem Version](https://badge.fury.io/rb/taipo.svg)](https://badge.fury.io/rb/taipo) [![Inline docs](http://inch-ci.org/github/pyrmont/taipo.svg?branch=master)](http://inch-ci.org/github/pyrmont/taipo)
|
2
|
+
|
1
3
|
# Taipo
|
2
4
|
|
3
5
|
Taipo is a simple library for checking the types of variables.
|
4
6
|
|
7
|
+
[Full documentation][rd] is available at RubyDoc.
|
8
|
+
|
9
|
+
[rd]: http://www.rubydoc.info/gems/taipo/index
|
10
|
+
|
5
11
|
## Overview
|
6
12
|
|
7
13
|
When we deal with variables in our code, we have certain expectations about what those variables can and can’t do.
|
@@ -14,18 +20,18 @@ Run `gem install taipo` or add `gem 'taipo'` to your `Gemfile`.
|
|
14
20
|
|
15
21
|
## Usage
|
16
22
|
|
17
|
-
Taipo provides two methods that we can mix into our classes: `#check` and `#review`.
|
23
|
+
Taipo provides two methods in the `Taipo::Check` module that we can mix into our classes: `#check` and `#review`.
|
18
24
|
|
19
25
|
### #check
|
20
26
|
|
21
|
-
```
|
27
|
+
```ruby
|
22
28
|
require ‘taipo’
|
23
29
|
|
24
30
|
class Foo
|
25
31
|
include Taipo::Check
|
26
|
-
|
32
|
+
|
27
33
|
def double(val)
|
28
|
-
check types, val: ‘Integer’
|
34
|
+
check types, val: ‘Integer’
|
29
35
|
val * 2
|
30
36
|
end
|
31
37
|
end
|
@@ -37,14 +43,18 @@ foo.double ‘Oops’ #=> Taipo::TypeError
|
|
37
43
|
|
38
44
|
The method `#check` will raise an exception as soon as one of its arguments doesn’t match its type definition.
|
39
45
|
|
46
|
+
[More information about `#check`][rdc] is available in the documentation.
|
47
|
+
|
48
|
+
[rdc]: http://www.rubydoc.info/gems/taipo/Taipo/Check#check-instance_method
|
49
|
+
|
40
50
|
### #review
|
41
51
|
|
42
|
-
```
|
52
|
+
```ruby
|
43
53
|
require ‘taipo’
|
44
54
|
|
45
55
|
class Foo
|
46
56
|
include Taipo::Check
|
47
|
-
|
57
|
+
|
48
58
|
def add(x, y)
|
49
59
|
errors = review types, x: ‘Integer’, y: ‘Integer’
|
50
60
|
if errors.empty?
|
@@ -62,26 +72,56 @@ foo.add 2, ‘OK’ #=> ‘Oops’
|
|
62
72
|
|
63
73
|
The method `#review` will put the invalid arguments into an array and return that to the user. If there are no errors, the array is empty.
|
64
74
|
|
75
|
+
[More information about `#review`][rdr] is available in the documentation.
|
76
|
+
|
77
|
+
[rdr]: http://www.rubydoc.info/gems/taipo/Taipo/Check#review-instance_method
|
78
|
+
|
65
79
|
## Syntax
|
66
80
|
|
67
|
-
Type definitions are
|
81
|
+
Type definitions are written as Strings. Type definitions can consist of (1) names, (2) collections, (3) constraints and (4) sums.
|
82
|
+
|
83
|
+
The information in this README is only meant as an introduction. [More information about the type definition syntax][rdv] is available in the documentation.
|
68
84
|
|
69
|
-
|
85
|
+
[rdv]: http://www.rubydoc.info/gems/taipo/Taipo/Parser/Validater
|
70
86
|
|
87
|
+
### Names
|
88
|
+
|
89
|
+
The simplest case is to write the name of a class. For example, `’String’`. Inherited class names can also be used.
|
90
|
+
|
91
|
+
```ruby
|
92
|
+
check types, a: 'String', b: 'Numeric'
|
71
93
|
```
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
'
|
76
|
-
|
77
|
-
|
78
|
-
'
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
94
|
+
|
95
|
+
#### Duck Types
|
96
|
+
|
97
|
+
It's possible to specify a duck type by writing the instance method (or methods) to which the object should respond.
|
98
|
+
|
99
|
+
```ruby
|
100
|
+
check types, a: '#to_s', b: '(#foo, #bar)'
|
101
|
+
```
|
102
|
+
|
103
|
+
### Collections
|
104
|
+
|
105
|
+
Taipo can also check whether a variable has a collection of elements of the specified child type. A child type can consist of the same components as any other type (ie. a name, collection, constraint, sum).
|
106
|
+
|
107
|
+
```ruby
|
108
|
+
check types, a: 'Array<Integer>', b: 'Hash<Symbol, String>', c: 'Array<Array<Float>>'
|
109
|
+
```
|
110
|
+
|
111
|
+
### Constraints
|
112
|
+
|
113
|
+
Constraints can be added to a type definition. Constraints consist of a list of one or more identifier-value pairs. Instance method names can also be in included.
|
114
|
+
|
115
|
+
```ruby
|
116
|
+
check types, a: 'Array(len: 5)', b: 'Integer(min: 0, max: 10)', c: 'String(format: /a{3}/)', d: 'String(val: "Hello world!")', e: 'Foo(#bar)'
|
117
|
+
```
|
118
|
+
|
119
|
+
### Sums
|
120
|
+
|
121
|
+
Type definitions can be combined to form sum types. Sum types consist of two or more type definitions.
|
122
|
+
|
123
|
+
```ruby
|
124
|
+
check types, a: 'String|Float', b: 'Boolean|Array<String|Hash<Symbol,Point>|Array<String>>', c: 'Integer(max: 100)|Float(max: 100)'
|
85
125
|
```
|
86
126
|
|
87
127
|
## Requirements
|
@@ -90,21 +130,25 @@ Taipo has been tested with Ruby version 2.4.2.
|
|
90
130
|
|
91
131
|
## Bugs
|
92
132
|
|
93
|
-
Found a bug? I’d love to know about it. The best way is to report them on GitHub.
|
133
|
+
Found a bug? I’d love to know about it. The best way is to report them in the [Issues section][ghi] on GitHub.
|
134
|
+
|
135
|
+
[ghi]: https://github.com/pyrmont/taipo/issues
|
94
136
|
|
95
|
-
##
|
137
|
+
## Contributing
|
96
138
|
|
97
139
|
If you’re interested in contributing to Taipo, feel free to fork and submit a pull request.
|
98
140
|
|
99
141
|
## Colophon
|
100
142
|
|
101
|
-
Taipo began as an exercise to improve my programming skills. If
|
143
|
+
Taipo began as, and remains primarily, an exercise to improve my programming skills. If Taipo has piqued your interest in adding type checks to Ruby, consider some of the other options, such as [Contracts][cnt], [Rtype][rty], [Rubype][rub] or [Sig][sig].
|
144
|
+
|
145
|
+
[cnt]: https://github.com/egonSchiele/contracts.ruby
|
146
|
+
[rty]: https://github.com/sputnikgugja/rtype
|
147
|
+
[rub]: https://github.com/gogotanaka/Rubype
|
148
|
+
[sig]: https://github.com/janlelis/sig
|
102
149
|
|
103
|
-
|
104
|
-
[2]: https://github.com/sputnikgugja/rtype
|
105
|
-
[3]: https://github.com/gogotanaka/Rubype
|
106
|
-
[4]: https://github.com/janlelis/sig
|
150
|
+
## Licence
|
107
151
|
|
108
|
-
|
152
|
+
Taipo is released into the public domain. See [LICENSE.md][lc] for more details.
|
109
153
|
|
110
|
-
|
154
|
+
[lc]: https://github.com/pyrmont/taipo/blob/master/LICENSE.md
|
@@ -3,8 +3,95 @@ require 'taipo/parser/syntax_state'
|
|
3
3
|
|
4
4
|
module Taipo
|
5
5
|
module Parser
|
6
|
-
|
6
|
+
|
7
7
|
# A validater of Taipo type definitions
|
8
|
+
#
|
9
|
+
# Taipo's type definition syntax has four components: (1) names; (2)
|
10
|
+
# collections; (3) constraints; and (4) sums.
|
11
|
+
#
|
12
|
+
# === Names
|
13
|
+
#
|
14
|
+
# 'String', 'Numeric'
|
15
|
+
#
|
16
|
+
# A name should be the name of a class or a module.
|
17
|
+
#
|
18
|
+
# The validater does not check whether the name represents a valid name in
|
19
|
+
# the current context nor does it check whether the name complies with
|
20
|
+
# Ruby's requirements for names. Either situation will cause an exception
|
21
|
+
# to be raised by {Taipo::Check#check} or {Taipo::Check#review}.
|
22
|
+
#
|
23
|
+
# One special case is where the name is left blank. The validater will
|
24
|
+
# accept this as valid. {Taipo::Parser} will implictly add the name
|
25
|
+
# 'Object' when parsing the type definition. This allows a clean syntax for
|
26
|
+
# duck types (which are really constraints on the class Object).
|
27
|
+
#
|
28
|
+
# === Collections
|
29
|
+
#
|
30
|
+
# 'Array<Integer>', 'Hash<Symbol, String>', 'Array<Array<Float>>'
|
31
|
+
#
|
32
|
+
# A collection should be the type definiton for elements returned by
|
33
|
+
# +Enumerator#each+ (the child type) called on the collecting object (the
|
34
|
+
# parent type).
|
35
|
+
#
|
36
|
+
# A collection is demarcated by the angle brackets +<+ and +>+. These come
|
37
|
+
# immediately after the name of the parent (ie. without a space). The type
|
38
|
+
# definition for the child comes immediately after the opening angle
|
39
|
+
# bracket.
|
40
|
+
#
|
41
|
+
# If +Enumerator#each+ returns multiple values (eg. such as with Hash), the
|
42
|
+
# type definition for each value is delimited by a comma. It is optional
|
43
|
+
# whether a space follows the comma.
|
44
|
+
#
|
45
|
+
# The type definition for a child element can contain all the components of
|
46
|
+
# a type definition (ie. name, collection, constraint, sum) allowing for
|
47
|
+
# collections that contain collections and so on.
|
48
|
+
#
|
49
|
+
# === Constraints
|
50
|
+
#
|
51
|
+
# 'Array(len: 5)', 'Integer(min: 0, max: 10)', 'String(format: /a{3}/)',
|
52
|
+
# 'String(val: "Hello world!")', 'Foo(#bar)'
|
53
|
+
#
|
54
|
+
# A constraint should be a list of identifiers and values.
|
55
|
+
#
|
56
|
+
# A constraint is demarcated by parentheses (ie. +(+ and +)+). These come
|
57
|
+
# immediately after the name or collection (ie. without a space). The first
|
58
|
+
# identifier comes immediately after the opening parenthesis.
|
59
|
+
#
|
60
|
+
# An identifier and a value are separated by a colon (and an optional
|
61
|
+
# space). Multiple identifier-value pairs are delimited by a comma. It is
|
62
|
+
# optional whether a space follows the comma.
|
63
|
+
#
|
64
|
+
# The permitted identifiers and their values are as follows:
|
65
|
+
# - +format+: takes a regular expression demarcated by +/+
|
66
|
+
# - +len+: takes an integer
|
67
|
+
# - +max+: takes an integer
|
68
|
+
# - +min+: takes an integer
|
69
|
+
# - +val+: takes a number or a string demarcated by +"+
|
70
|
+
#
|
71
|
+
# The validater does not check whether the identifiers and values are
|
72
|
+
# acceptable, merely that they conform to the grammar.
|
73
|
+
# {Taipo::Parser.parse} will raise an exception when it parses the
|
74
|
+
# definition if the values are not acceptable for the relevant identifier.
|
75
|
+
# Similarly, while the repetition of an identifier is technically invalid,
|
76
|
+
# the exception will not be raised until {Taipo::Parser.parse} is called.
|
77
|
+
#
|
78
|
+
# One special case is where the identifier begins with a +#+. For this
|
79
|
+
# identifier, no value is provided and the constraint instead results in
|
80
|
+
# {Taipo::Check#check} and {Taipo::Check#review} checking whether the
|
81
|
+
# given object returns true for +Object#respond_to?+ with the identifier as
|
82
|
+
# the symbol.
|
83
|
+
#
|
84
|
+
# === Sums
|
85
|
+
#
|
86
|
+
# 'String|Float',
|
87
|
+
# 'Boolean|Array<String|Hash<Symbol,Point>|Array<String>>',
|
88
|
+
# 'Integer(max: 100)|Float(max: 100)'
|
89
|
+
#
|
90
|
+
# A sum is a combination of two or more type definitions.
|
91
|
+
#
|
92
|
+
# The sum comprises two or more type definitions, each separated by a bar
|
93
|
+
# (ie. +|+).
|
94
|
+
#
|
8
95
|
# @since 1.0.0
|
9
96
|
module Validater
|
10
97
|
|
@@ -12,8 +99,10 @@ module Taipo
|
|
12
99
|
#
|
13
100
|
# @param str [String] a type definition
|
14
101
|
#
|
102
|
+
# @return [NilClass]
|
103
|
+
#
|
15
104
|
# @raise [::TypeError] if +str+ is not a String
|
16
|
-
# @raise [Taipo::SyntaxError] if +str+ is not a valid type definition
|
105
|
+
# @raise [Taipo::SyntaxError] if +str+ is not a valid type definition
|
17
106
|
#
|
18
107
|
# @since 1.0.0
|
19
108
|
def self.validate(str)
|
data/lib/taipo/version.rb
CHANGED
data/lib/taipo.rb
CHANGED
@@ -3,14 +3,30 @@ require 'taipo/check'
|
|
3
3
|
require 'taipo/parser'
|
4
4
|
|
5
5
|
# A library for checking the types of objects
|
6
|
-
#
|
6
|
+
#
|
7
|
+
# Taipo is primarily intended as a replacement for cumbersome, error-prone
|
8
|
+
# guard statements a user can put in their code to ensure that the variables
|
9
|
+
# they are handling conform to expectations.
|
10
|
+
#
|
11
|
+
# By including the module {Taipo::Check}, a user can call the
|
12
|
+
# {Taipo::Check#check} or {Taipo::Check#review} methods in their classes
|
13
|
+
# whenever a guard statement is necessary. Expectations are written as type
|
14
|
+
# definitions that can specify the type of the variable (including sum types)
|
15
|
+
# and the types of any elements it contains, all subject to a given constraints
|
16
|
+
# (see {Taipo::Parser::Validater} for the full syntax).
|
17
|
+
#
|
18
|
+
# As syntactic sugar, the {Taipo::Check} module also aliases +Kernel#binding+
|
19
|
+
# with the keyword +types+. This allows the user to call {Taipo::Check#check}
|
20
|
+
# and {Taipo::Check#review} by writing +check types, ...+ and
|
21
|
+
# +review types, ...+ respectively.
|
22
|
+
#
|
7
23
|
# @since 1.0.0
|
8
|
-
# @see https://github.com/pyrmont/
|
24
|
+
# @see https://github.com/pyrmont/taipo
|
9
25
|
module Taipo
|
10
26
|
|
11
27
|
# Check if a string is the name of an instance method
|
12
28
|
#
|
13
|
-
# @note All this does is check whether the given string begins with a hash
|
29
|
+
# @note All this does is check whether the given string begins with a hash
|
14
30
|
# symbol.
|
15
31
|
#
|
16
32
|
# @param str [String] the method name to check
|
data/taipo.gemspec
CHANGED
@@ -12,9 +12,11 @@ Gem::Specification.new do |spec|
|
|
12
12
|
spec.summary = %q{A simple library for checking the types of variables.}
|
13
13
|
spec.description = %q{Taipo provides a simple way to check your variables are what you think they are. With an easy to use syntax you can call a single method and pass expressive type definitions.}
|
14
14
|
spec.homepage = "https://github.com/pyrmont/taipo/"
|
15
|
+
spec.license = "Unlicense"
|
15
16
|
|
16
17
|
spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
|
17
18
|
spec.require_paths = ["lib"]
|
19
|
+
spec.required_ruby_version = '>= 2.4.0'
|
18
20
|
|
19
21
|
spec.metadata['allowed_push_host'] = 'https://rubygems.org'
|
20
22
|
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: taipo
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.0.
|
4
|
+
version: 1.0.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Michael Camilleri
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2018-01-
|
11
|
+
date: 2018-01-19 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -124,7 +124,8 @@ files:
|
|
124
124
|
- lib/taipo/version.rb
|
125
125
|
- taipo.gemspec
|
126
126
|
homepage: https://github.com/pyrmont/taipo/
|
127
|
-
licenses:
|
127
|
+
licenses:
|
128
|
+
- Unlicense
|
128
129
|
metadata:
|
129
130
|
allowed_push_host: https://rubygems.org
|
130
131
|
post_install_message:
|
@@ -135,7 +136,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
135
136
|
requirements:
|
136
137
|
- - ">="
|
137
138
|
- !ruby/object:Gem::Version
|
138
|
-
version:
|
139
|
+
version: 2.4.0
|
139
140
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
140
141
|
requirements:
|
141
142
|
- - ">="
|