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