typerb 0.1.6 → 0.1.7
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 +4 -4
- data/.gitignore +1 -0
- data/.rubocop.yml +1 -0
- data/Gemfile.lock +34 -1
- data/Guardfile +36 -0
- data/README.md +23 -9
- data/lib/typerb/exceptional.rb +4 -0
- data/lib/typerb/version.rb +1 -1
- data/lib/typerb.rb +14 -0
- data/typerb.gemspec +2 -0
- metadata +31 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: f7cef67daf67692e132e69a417bc8d7ea8162c56e87f7c058b5d095aed720506
|
4
|
+
data.tar.gz: 8493a01a0310fe1accb703ee82515b8f59163dc4069117774df00fafd0228113
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: e69f6c28e078a84bded21be966969c7979ab71f26dff4379b7952026c3ea180422ac68ae82b4e2ef003cd34cb47fd0902f474024758ff756984aaa0f937a7eae
|
7
|
+
data.tar.gz: f5ea90611dbd4429a48b11b59ce69d2e6f4e267e7d451916171bb06f680e64f6bec033f1f31dd7c6c6096f510123d1dc2b0aa50932630c0ec6406022bb81e2e9
|
data/.gitignore
CHANGED
data/.rubocop.yml
CHANGED
data/Gemfile.lock
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
PATH
|
2
2
|
remote: .
|
3
3
|
specs:
|
4
|
-
typerb (0.1.
|
4
|
+
typerb (0.1.7)
|
5
5
|
|
6
6
|
GEM
|
7
7
|
remote: https://rubygems.org/
|
@@ -10,8 +10,33 @@ GEM
|
|
10
10
|
awesome_print (1.8.0)
|
11
11
|
coderay (1.1.2)
|
12
12
|
diff-lcs (1.3)
|
13
|
+
ffi (1.9.25)
|
14
|
+
formatador (0.2.5)
|
15
|
+
guard (2.14.2)
|
16
|
+
formatador (>= 0.2.4)
|
17
|
+
listen (>= 2.7, < 4.0)
|
18
|
+
lumberjack (>= 1.0.12, < 2.0)
|
19
|
+
nenv (~> 0.1)
|
20
|
+
notiffany (~> 0.0)
|
21
|
+
pry (>= 0.9.12)
|
22
|
+
shellany (~> 0.0)
|
23
|
+
thor (>= 0.18.1)
|
24
|
+
guard-compat (1.2.1)
|
25
|
+
guard-rspec (4.7.3)
|
26
|
+
guard (~> 2.1)
|
27
|
+
guard-compat (~> 1.1)
|
28
|
+
rspec (>= 2.99.0, < 4.0)
|
13
29
|
jaro_winkler (1.5.1)
|
30
|
+
listen (3.1.5)
|
31
|
+
rb-fsevent (~> 0.9, >= 0.9.4)
|
32
|
+
rb-inotify (~> 0.9, >= 0.9.7)
|
33
|
+
ruby_dep (~> 1.2)
|
34
|
+
lumberjack (1.0.13)
|
14
35
|
method_source (0.9.1)
|
36
|
+
nenv (0.3.0)
|
37
|
+
notiffany (0.1.1)
|
38
|
+
nenv (~> 0.1)
|
39
|
+
shellany (~> 0.0)
|
15
40
|
parallel (1.12.1)
|
16
41
|
parser (2.5.3.0)
|
17
42
|
ast (~> 2.4.0)
|
@@ -21,6 +46,9 @@ GEM
|
|
21
46
|
method_source (~> 0.9.0)
|
22
47
|
rainbow (3.0.0)
|
23
48
|
rake (10.5.0)
|
49
|
+
rb-fsevent (0.10.3)
|
50
|
+
rb-inotify (0.9.10)
|
51
|
+
ffi (>= 0.5.0, < 2)
|
24
52
|
rspec (3.8.0)
|
25
53
|
rspec-core (~> 3.8.0)
|
26
54
|
rspec-expectations (~> 3.8.0)
|
@@ -43,8 +71,11 @@ GEM
|
|
43
71
|
ruby-progressbar (~> 1.7)
|
44
72
|
unicode-display_width (~> 1.4.0)
|
45
73
|
ruby-progressbar (1.10.0)
|
74
|
+
ruby_dep (1.5.0)
|
75
|
+
shellany (0.0.1)
|
46
76
|
super_awesome_print (0.2.5)
|
47
77
|
awesome_print
|
78
|
+
thor (0.20.0)
|
48
79
|
unicode-display_width (1.4.0)
|
49
80
|
|
50
81
|
PLATFORMS
|
@@ -52,6 +83,8 @@ PLATFORMS
|
|
52
83
|
|
53
84
|
DEPENDENCIES
|
54
85
|
bundler (>= 1.17)
|
86
|
+
guard
|
87
|
+
guard-rspec
|
55
88
|
pry
|
56
89
|
rake (>= 10.0)
|
57
90
|
rspec (>= 3.0)
|
data/Guardfile
ADDED
@@ -0,0 +1,36 @@
|
|
1
|
+
# A sample Guardfile
|
2
|
+
# More info at https://github.com/guard/guard#readme
|
3
|
+
|
4
|
+
## Uncomment and set this to only include directories you want to watch
|
5
|
+
# directories %w(app lib config test spec features) \
|
6
|
+
# .select{|d| Dir.exists?(d) ? d : UI.warning("Directory #{d} does not exist")}
|
7
|
+
|
8
|
+
## Note: if you are using the `directories` clause above and you are not
|
9
|
+
## watching the project directory ('.'), then you will want to move
|
10
|
+
## the Guardfile to a watched dir and symlink it back, e.g.
|
11
|
+
#
|
12
|
+
# $ mkdir config
|
13
|
+
# $ mv Guardfile config/
|
14
|
+
# $ ln -s config/Guardfile .
|
15
|
+
#
|
16
|
+
# and, you'll have to watch "config/Guardfile" instead of "Guardfile"
|
17
|
+
guard :rspec, cmd: "bundle exec rspec" do
|
18
|
+
require "guard/rspec/dsl"
|
19
|
+
dsl = Guard::RSpec::Dsl.new(self)
|
20
|
+
|
21
|
+
# Feel free to open issues for suggestions and improvements
|
22
|
+
|
23
|
+
# RSpec files
|
24
|
+
rspec = dsl.rspec
|
25
|
+
watch(rspec.spec_helper) { rspec.spec_dir }
|
26
|
+
watch(rspec.spec_support) { rspec.spec_dir }
|
27
|
+
watch(rspec.spec_files)
|
28
|
+
|
29
|
+
# Ruby files
|
30
|
+
ruby = dsl.ruby
|
31
|
+
dsl.watch_spec_files_for(ruby.lib_files)
|
32
|
+
|
33
|
+
|
34
|
+
# watch(rails.routes) { "#{rspec.spec_dir}/routing" }
|
35
|
+
# watch(rails.app_controller) { "#{rspec.spec_dir}/controllers" }
|
36
|
+
end
|
data/README.md
CHANGED
@@ -3,7 +3,7 @@
|
|
3
3
|
|
4
4
|
# Typerb
|
5
5
|
|
6
|
-
Proof of concept type-checking library for Ruby 2.6.
|
6
|
+
Proof of concept type-checking library for Ruby 2.6. Works with previous versions too with some limitation (see below).
|
7
7
|
|
8
8
|
```ruby
|
9
9
|
class A
|
@@ -12,9 +12,15 @@ class A
|
|
12
12
|
def call(some_arg)
|
13
13
|
some_arg.type!(String, Symbol)
|
14
14
|
end
|
15
|
+
|
16
|
+
def call_with_respond_checks(some_arg)
|
17
|
+
some_arg.respond_to!(:strip)
|
18
|
+
end
|
19
|
+
|
15
20
|
end
|
16
21
|
|
17
22
|
A.new.call(1) #=> TypeError: `some_arg` should be String or Symbol, not Integer
|
23
|
+
A.new.call_with_respond_checks(1) #=> TypeError: 'Integer should respond to all methods: strip'
|
18
24
|
```
|
19
25
|
|
20
26
|
This is equivalent to:
|
@@ -23,6 +29,10 @@ class A
|
|
23
29
|
def call(some_arg)
|
24
30
|
raise TypeError, "`some_arg` should be String or Symbol, not #{some_arg.class}" unless [String, Symbol].include?(some_arg.class)
|
25
31
|
end
|
32
|
+
|
33
|
+
def call_with_respond_checks(some_arg)
|
34
|
+
raise TypeError, "#{some_arg.class} should respond to all methods: strip" unless [:strip].all{|meth| some_arg.respond_to?(meth)}
|
35
|
+
end
|
26
36
|
end
|
27
37
|
```
|
28
38
|
|
@@ -90,13 +100,13 @@ end
|
|
90
100
|
|
91
101
|
If you're unfamiliar with `using` keyword - this is refinement - a relatively new feature in Ruby (since 2.0). It's kind of monkey-patch, but with strict scope. Learn more about [refinements](https://ruby-doc.org/core-2.5.3/doc/syntax/refinements_rdoc.html).
|
92
102
|
|
93
|
-
This refinement adds `type!()`
|
103
|
+
This refinement adds `type!()` and `not_nil!` methods to `Object` class so you can call it on almost much any object (except those inherited from `BasicObject`, but these are rare).
|
94
104
|
|
95
105
|
The method will raise an exception if `self` is not an instance of one of the classes passed as arguments. The tricky part, however, is to get the variable name on which it's called. You need this to get a nice error message telling you exactly which variable has wrong type, not just an abstract `TypeError`. That's why we need Ruby 2.6 with its new `RubyVM::AST` (https://ruby-doc.org/core-2.6.0.preview3/RubyVM/AST.html).
|
96
106
|
|
97
107
|
## Limitations
|
98
108
|
|
99
|
-
|
109
|
+
Full functionality Ruby 2.6.0-preview3. Relies on `RubyVM::AST` which may change in release version. So, expect breaking changes in Ruby. Previous versions also supported, but without variable name in exception message.
|
100
110
|
|
101
111
|
Known limitations:
|
102
112
|
|
@@ -107,8 +117,9 @@ class A
|
|
107
117
|
|
108
118
|
def call(some_arg)
|
109
119
|
some_arg.
|
110
|
-
type!(String)
|
111
|
-
|
120
|
+
type!(String)
|
121
|
+
# this won't work. type!() call must be on the same line with the variable it's called on - raise error message without variable name
|
122
|
+
# some_arg. type!(String) is ok though
|
112
123
|
end
|
113
124
|
end
|
114
125
|
```
|
@@ -119,10 +130,11 @@ end
|
|
119
130
|
[1] pry(main)* using Typerb
|
120
131
|
[1] pry(main)* def call(a)
|
121
132
|
[1] pry(main)* a.type!(Hash)
|
122
|
-
[1] pry(main)* end
|
123
|
-
[1] pry(main)* end
|
133
|
+
[1] pry(main)* end
|
134
|
+
[1] pry(main)* end
|
124
135
|
[2] pry(main)> A.new.call(1)
|
125
|
-
TypeError: expected Hash, got Integer
|
136
|
+
TypeError: expected Hash, got Integer
|
137
|
+
# here we cannot get the source code for a line containing "a.type!(Hash)", so cannot see the variable name
|
126
138
|
```
|
127
139
|
|
128
140
|
3. Multiple arguments on the same line:
|
@@ -131,7 +143,9 @@ class A
|
|
131
143
|
using Typerb
|
132
144
|
|
133
145
|
def initialize(arg1, arg2)
|
134
|
-
arg1.type!(Integer); arg2.type!(String)
|
146
|
+
arg1.type!(Integer); arg2.type!(String)
|
147
|
+
# no way to tell the variable - raise error message without variable name
|
148
|
+
# same error will be raised on Ruby < 2.6.0 because there is no RubyVM::AST
|
135
149
|
end
|
136
150
|
end
|
137
151
|
```
|
data/lib/typerb/exceptional.rb
CHANGED
data/lib/typerb/version.rb
CHANGED
data/lib/typerb.rb
CHANGED
@@ -31,5 +31,19 @@ module Typerb
|
|
31
31
|
|
32
32
|
Typerb::Exceptional.new.raise_with(caller, exception_text)
|
33
33
|
end
|
34
|
+
|
35
|
+
def respond_to!(*methods)
|
36
|
+
raise ArgumentError, 'provide at least one method' if methods.empty?
|
37
|
+
return self if methods.all? { |meth| respond_to?(meth) }
|
38
|
+
|
39
|
+
methods_text = Typerb::Exceptional.methods_text(methods)
|
40
|
+
exception_text = if (var_name = Typerb::VariableName.new(caller_locations(1, 1)).get)
|
41
|
+
"#{self.class} (`#{var_name}`) should respond to all methods: #{methods_text}"
|
42
|
+
else
|
43
|
+
"#{self.class} should respond to all methods: #{methods_text}"
|
44
|
+
end
|
45
|
+
|
46
|
+
Typerb::Exceptional.new.raise_with(caller, exception_text)
|
47
|
+
end
|
34
48
|
end
|
35
49
|
end
|
data/typerb.gemspec
CHANGED
@@ -25,6 +25,8 @@ Gem::Specification.new do |spec|
|
|
25
25
|
spec.require_paths = ['lib']
|
26
26
|
|
27
27
|
spec.add_development_dependency 'bundler', '>= 1.17'
|
28
|
+
spec.add_development_dependency 'guard'
|
29
|
+
spec.add_development_dependency 'guard-rspec'
|
28
30
|
spec.add_development_dependency 'pry'
|
29
31
|
spec.add_development_dependency 'rake', '>= 10.0'
|
30
32
|
spec.add_development_dependency 'rspec', '>= 3.0'
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: typerb
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1.
|
4
|
+
version: 0.1.7
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Oleg Antonyan
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2018-11-
|
11
|
+
date: 2018-11-15 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -24,6 +24,34 @@ dependencies:
|
|
24
24
|
- - ">="
|
25
25
|
- !ruby/object:Gem::Version
|
26
26
|
version: '1.17'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: guard
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - ">="
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '0'
|
34
|
+
type: :development
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - ">="
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '0'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: guard-rspec
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - ">="
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '0'
|
48
|
+
type: :development
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - ">="
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '0'
|
27
55
|
- !ruby/object:Gem::Dependency
|
28
56
|
name: pry
|
29
57
|
requirement: !ruby/object:Gem::Requirement
|
@@ -109,6 +137,7 @@ files:
|
|
109
137
|
- CODE_OF_CONDUCT.md
|
110
138
|
- Gemfile
|
111
139
|
- Gemfile.lock
|
140
|
+
- Guardfile
|
112
141
|
- LICENSE.txt
|
113
142
|
- README.md
|
114
143
|
- Rakefile
|