typerb 0.3.0 → 0.5.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 +4 -4
- data/CHANGELOG.md +18 -0
- data/README.md +57 -56
- data/lib/typerb/exceptional.rb +5 -17
- data/lib/typerb/prism_parser.rb +67 -0
- data/lib/typerb/ruby_vm_parser.rb +57 -0
- data/lib/typerb/source_cache.rb +30 -0
- data/lib/typerb/variable_name.rb +18 -14
- data/lib/typerb/version.rb +1 -1
- data/lib/typerb.rb +28 -32
- metadata +18 -94
- data/.gitignore +0 -15
- data/.rspec +0 -3
- data/.rubocop.yml +0 -21
- data/.ruby-version +0 -1
- data/.travis.yml +0 -15
- data/Gemfile +0 -8
- data/Gemfile.lock +0 -94
- data/Guardfile +0 -36
- data/Rakefile +0 -8
- data/bin/console +0 -14
- data/bin/setup +0 -8
- data/typerb.gemspec +0 -37
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 548c823e7f9d7185d069b2bb18f370bdcb8b18603e82de22b78712c251dc4a14
|
|
4
|
+
data.tar.gz: 637a184fa56802fdb93a60020e7eb633692e606726215dce533de62367edd3fe
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: d1cf6e4223cae7543e133ede58d02a0016e8566501e1642afd85aa36ffea47e09ce3a0135fe81bd805461dc5dd163c546d5b65148f19bc1ebbab75694dbb05bf
|
|
7
|
+
data.tar.gz: '0486a293dea0eca23bdd4aa56f02a0a7fdd4c35d7d317a3c34683930f5642b903714c974a63a2b06533809703fecb549716e8e300b5d4248b1b84d4a7ce1ee3f'
|
data/CHANGELOG.md
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
## 0.5.0
|
|
4
|
+
|
|
5
|
+
- Variable name detection rewritten: the whole caller file is parsed instead of a single stripped line.
|
|
6
|
+
Prism is used on Ruby 3.3+, `RubyVM::AbstractSyntaxTree` on 3.0-3.2. Both backends behave identically.
|
|
7
|
+
- Fixed `SyntaxError` escaping from `type!` and friends when the call spanned several lines
|
|
8
|
+
(leading-dot chains, multi-line argument lists).
|
|
9
|
+
- Variable name is now reported for multi-line calls, assignments, string interpolation and chained
|
|
10
|
+
receivers (`h.fetch(:a).type!(String)`).
|
|
11
|
+
- `subset_of!` raises `ArgumentError` instead of `NoMethodError` when the receiver is not `Enumerable`.
|
|
12
|
+
- Variable names are reported correctly on lines containing multibyte characters.
|
|
13
|
+
- Minimum Ruby is 3.0.
|
|
14
|
+
- Removed Guard from development dependencies.
|
|
15
|
+
|
|
16
|
+
## 0.4.0
|
|
17
|
+
|
|
18
|
+
- Added `subset_of!`.
|
data/README.md
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
[](https://badge.fury.io/rb/typerb)
|
|
2
|
-
[](https://github.com/olegantonyan/typerb/actions/workflows/tests.yml)
|
|
3
3
|
|
|
4
4
|
# Typerb
|
|
5
5
|
|
|
6
|
-
|
|
6
|
+
Typecheck sugar for Ruby. Requires Ruby 3.0 or newer.
|
|
7
7
|
|
|
8
8
|
```ruby
|
|
9
9
|
class A
|
|
@@ -20,29 +20,35 @@ class A
|
|
|
20
20
|
def call_with_enum(arg)
|
|
21
21
|
arg.enum!(:one, :two)
|
|
22
22
|
end
|
|
23
|
+
|
|
24
|
+
def call_with_subset(arg)
|
|
25
|
+
arg.subset_of!(%i[one two])
|
|
26
|
+
end
|
|
23
27
|
end
|
|
24
28
|
|
|
25
|
-
A.new.call(1)
|
|
26
|
-
A.new.call_with_respond_checks(1)
|
|
27
|
-
A.new.call_with_enum(:three)
|
|
29
|
+
A.new.call(1) #=> TypeError: `some_arg` should be String or Symbol, not Integer (1)
|
|
30
|
+
A.new.call_with_respond_checks(1) #=> TypeError: Integer (`some_arg`) should respond to all methods: strip
|
|
31
|
+
A.new.call_with_enum(:three) #=> TypeError: Symbol (`arg`) should be one of: [one, two], not three
|
|
32
|
+
A.new.call_with_subset(%i[one three]) #=> TypeError: Array (`arg`) should be subset of: [:one, :two], not [:one, :three]
|
|
28
33
|
```
|
|
29
34
|
|
|
30
35
|
This is equivalent to:
|
|
36
|
+
|
|
31
37
|
```ruby
|
|
32
38
|
class A
|
|
33
39
|
def call(some_arg)
|
|
34
|
-
raise TypeError, "`some_arg` should be String or Symbol, not #{some_arg.class}" unless
|
|
40
|
+
raise TypeError, "`some_arg` should be String or Symbol, not #{some_arg.class}" unless some_arg.is_a?(String) || some_arg.is_a?(Symbol)
|
|
35
41
|
end
|
|
36
42
|
|
|
37
43
|
def call_with_respond_checks(some_arg)
|
|
38
|
-
raise TypeError, "#{some_arg.class} should respond to all methods: strip" unless [
|
|
44
|
+
raise TypeError, "#{some_arg.class} should respond to all methods: strip" unless %i[strip].all? { |meth| some_arg.respond_to?(meth) }
|
|
39
45
|
end
|
|
40
46
|
end
|
|
41
47
|
```
|
|
42
48
|
|
|
43
|
-
But without boilerplate.
|
|
49
|
+
But without the boilerplate.
|
|
44
50
|
|
|
45
|
-
|
|
51
|
+
There is also a `not_nil!` method, similar to the Crystal language.
|
|
46
52
|
|
|
47
53
|
```ruby
|
|
48
54
|
class A
|
|
@@ -53,13 +59,15 @@ class A
|
|
|
53
59
|
end
|
|
54
60
|
end
|
|
55
61
|
|
|
56
|
-
A.new.call(nil) #=> TypeError:
|
|
62
|
+
A.new.call(nil) #=> TypeError: `some_arg` should not be nil
|
|
57
63
|
```
|
|
58
64
|
|
|
65
|
+
Every method returns `self` when the check passes, so checks can be chained or inlined into assignments.
|
|
66
|
+
|
|
59
67
|
## Why?
|
|
60
68
|
|
|
61
|
-
1. Catch
|
|
62
|
-
2. Additional documentation: you're telling other people more about interfaces.
|
|
69
|
+
1. Catch errors as early as possible (especially nils);
|
|
70
|
+
2. Additional documentation: you're telling other people more about your interfaces.
|
|
63
71
|
|
|
64
72
|
## Installation
|
|
65
73
|
|
|
@@ -77,20 +85,9 @@ Or install it yourself as:
|
|
|
77
85
|
|
|
78
86
|
$ gem install typerb
|
|
79
87
|
|
|
80
|
-
If this fails with error
|
|
81
|
-
```
|
|
82
|
-
ERROR: Error installing typerb:
|
|
83
|
-
There are no versions of typerb (>= 0) compatible with your Ruby & RubyGems
|
|
84
|
-
typerb requires Ruby version >= 2.6.0.pre.preview3. The current ruby version is 2.6.0.
|
|
85
|
-
```
|
|
86
|
-
even when you have Ruby 2.6.0-preview3 installed, then try installing it through Gemfile from git:
|
|
87
|
-
```ruby
|
|
88
|
-
gem 'typerb', github: 'olegantonyan/typerb'
|
|
89
|
-
```
|
|
90
|
-
|
|
91
88
|
## Usage
|
|
92
89
|
|
|
93
|
-
1. Add `using Typerb` to a class where you want to have type
|
|
90
|
+
1. Add `using Typerb` to a class where you want to have type checks.
|
|
94
91
|
2. Call `.type!()` on any object to assert its type.
|
|
95
92
|
3. PROFIT! No more "NoMethodError for nil" 10 methods up the stack. You'll know exactly where this nil came from.
|
|
96
93
|
|
|
@@ -107,33 +104,44 @@ class A
|
|
|
107
104
|
end
|
|
108
105
|
```
|
|
109
106
|
|
|
110
|
-
If you're unfamiliar with `using` keyword - this is refinement
|
|
107
|
+
If you're unfamiliar with the `using` keyword - this is a refinement, a kind of monkey patch with a strict
|
|
108
|
+
scope. Learn more about [refinements](https://docs.ruby-lang.org/en/master/syntax/refinements_rdoc.html).
|
|
109
|
+
|
|
110
|
+
The refinement adds `type!`, `not_nil!`, `respond_to!`, `enum!` and `subset_of!` to `BasicObject`, so
|
|
111
|
+
they can be called on any object.
|
|
111
112
|
|
|
112
|
-
|
|
113
|
+
`type!` raises a `TypeError` unless `self` is an instance of one of the classes passed as arguments.
|
|
114
|
+
The tricky part is getting the name of the variable it was called on, so that the error message points at
|
|
115
|
+
the exact variable instead of being an abstract `TypeError`. Typerb does that by parsing the source file
|
|
116
|
+
of the caller: with [Prism](https://github.com/ruby/prism) on Ruby 3.3+, and with `RubyVM::AbstractSyntaxTree`
|
|
117
|
+
on older versions. If neither is available, or the source cannot be read, the check still works - the message
|
|
118
|
+
just doesn't name the variable.
|
|
113
119
|
|
|
114
|
-
|
|
120
|
+
| Ruby | Parser |
|
|
121
|
+
| --------- | ---------------------------- |
|
|
122
|
+
| 3.3+ | Prism |
|
|
123
|
+
| 3.0 - 3.2 | `RubyVM::AbstractSyntaxTree` |
|
|
124
|
+
|
|
125
|
+
Both parsers produce the same messages, and CI runs the suite against every supported version.
|
|
115
126
|
|
|
116
127
|
## Limitations
|
|
117
128
|
|
|
118
|
-
|
|
129
|
+
The variable name is omitted (the check itself still works) in two cases.
|
|
119
130
|
|
|
120
|
-
|
|
131
|
+
1. Several checks on the same line - there is no way to tell which one raised:
|
|
121
132
|
|
|
122
|
-
1. Multi-line method call:
|
|
123
133
|
```ruby
|
|
124
134
|
class A
|
|
125
135
|
using Typerb
|
|
126
136
|
|
|
127
|
-
def
|
|
128
|
-
|
|
129
|
-
type!(String)
|
|
130
|
-
# 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
|
|
131
|
-
# some_arg. type!(String) is ok though
|
|
137
|
+
def initialize(arg1, arg2)
|
|
138
|
+
arg1.type!(Integer); arg2.type!(String)
|
|
132
139
|
end
|
|
133
140
|
end
|
|
134
141
|
```
|
|
135
142
|
|
|
136
|
-
2.
|
|
143
|
+
2. Code whose source file cannot be read - `eval`, a console session, or a file deleted after being loaded:
|
|
144
|
+
|
|
137
145
|
```ruby
|
|
138
146
|
[1] pry(main)> class A
|
|
139
147
|
[1] pry(main)* using Typerb
|
|
@@ -142,34 +150,26 @@ end
|
|
|
142
150
|
[1] pry(main)* end
|
|
143
151
|
[1] pry(main)* end
|
|
144
152
|
[2] pry(main)> A.new.call(1)
|
|
145
|
-
TypeError: expected Hash, got Integer
|
|
146
|
-
# here we cannot get the source code for a line containing "a.type!(Hash)", so cannot see the variable name
|
|
147
|
-
```
|
|
148
|
-
|
|
149
|
-
3. Multiple arguments on the same line:
|
|
150
|
-
```ruby
|
|
151
|
-
class A
|
|
152
|
-
using Typerb
|
|
153
|
-
|
|
154
|
-
def initialize(arg1, arg2)
|
|
155
|
-
arg1.type!(Integer); arg2.type!(String)
|
|
156
|
-
# no way to tell the variable - raise error message without variable name
|
|
157
|
-
# same error will be raised on Ruby < 2.6.0 because there is no RubyVM::AST
|
|
158
|
-
end
|
|
159
|
-
end
|
|
153
|
+
TypeError: expected Hash, got Integer (1)
|
|
160
154
|
```
|
|
161
155
|
|
|
162
|
-
|
|
156
|
+
Please file an issue if you know a scenario where one of these is a real problem.
|
|
163
157
|
|
|
164
158
|
## Development
|
|
165
159
|
|
|
166
|
-
After checking out the repo, run `bin/setup` to install dependencies. Then
|
|
160
|
+
After checking out the repo, run `bin/setup` to install dependencies. Then run `rake test` to run the tests.
|
|
161
|
+
You can also run `bin/console` for an interactive prompt that will allow you to experiment.
|
|
167
162
|
|
|
168
|
-
To install this gem onto your local machine, run `bundle exec rake install`. To release a new version,
|
|
163
|
+
To install this gem onto your local machine, run `bundle exec rake install`. To release a new version,
|
|
164
|
+
update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git
|
|
165
|
+
tag for the version, push git commits and tags, and push the `.gem` file to
|
|
166
|
+
[rubygems.org](https://rubygems.org).
|
|
169
167
|
|
|
170
168
|
## Contributing
|
|
171
169
|
|
|
172
|
-
Bug reports and pull requests are welcome on GitHub at https://github.com/olegantonyan/typerb. This project
|
|
170
|
+
Bug reports and pull requests are welcome on GitHub at https://github.com/olegantonyan/typerb. This project
|
|
171
|
+
is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the
|
|
172
|
+
[Contributor Covenant](http://contributor-covenant.org) code of conduct.
|
|
173
173
|
|
|
174
174
|
## License
|
|
175
175
|
|
|
@@ -177,4 +177,5 @@ The gem is available as open source under the terms of the [MIT License](https:/
|
|
|
177
177
|
|
|
178
178
|
## Code of Conduct
|
|
179
179
|
|
|
180
|
-
Everyone interacting in the Typerb project
|
|
180
|
+
Everyone interacting in the Typerb project's codebases, issue trackers, chat rooms and mailing lists is
|
|
181
|
+
expected to follow the [code of conduct](https://github.com/olegantonyan/typerb/blob/master/CODE_OF_CONDUCT.md).
|
data/lib/typerb/exceptional.rb
CHANGED
|
@@ -1,23 +1,11 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
class Exceptional # NOTE: don't want to collide with 'Exception' class name
|
|
5
|
-
class << self
|
|
6
|
-
def klasses_text(klasses)
|
|
7
|
-
klasses.size > 1 ? klasses.map(&:name).join(' or ') : klasses.first.name
|
|
8
|
-
end
|
|
9
|
-
|
|
10
|
-
def methods_text(methods)
|
|
11
|
-
methods.join(', ')
|
|
12
|
-
end
|
|
3
|
+
require 'typerb/variable_name'
|
|
13
4
|
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
def raise_with(backtrace, exception_text)
|
|
20
|
-
exception = TypeError.new(exception_text)
|
|
5
|
+
module Typerb
|
|
6
|
+
module Exceptional # NOTE: don't want to collide with 'Exception' class name
|
|
7
|
+
def self.raise_type_error(backtrace, location, method_name)
|
|
8
|
+
exception = TypeError.new(yield(VariableName.new(location, method_name).get))
|
|
21
9
|
exception.set_backtrace(backtrace)
|
|
22
10
|
raise exception
|
|
23
11
|
end
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
begin
|
|
4
|
+
require 'prism'
|
|
5
|
+
rescue LoadError # rubocop: disable Lint/SuppressedException
|
|
6
|
+
end
|
|
7
|
+
|
|
8
|
+
require 'typerb/source_cache'
|
|
9
|
+
|
|
10
|
+
module Typerb
|
|
11
|
+
module PrismParser
|
|
12
|
+
RECEIVER_NODE_NAMES = %w[
|
|
13
|
+
LocalVariableReadNode
|
|
14
|
+
InstanceVariableReadNode
|
|
15
|
+
ClassVariableReadNode
|
|
16
|
+
GlobalVariableReadNode
|
|
17
|
+
ConstantReadNode
|
|
18
|
+
ConstantPathNode
|
|
19
|
+
CallNode
|
|
20
|
+
].freeze
|
|
21
|
+
|
|
22
|
+
class << self
|
|
23
|
+
def available?
|
|
24
|
+
defined?(::Prism) && ::Prism.respond_to?(:parse_file)
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
def receiver_sources(file, line, method_name)
|
|
28
|
+
calls(root(file), line, method_name).map { |node| receiver_source(node) }
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
private
|
|
32
|
+
|
|
33
|
+
def root(file)
|
|
34
|
+
SourceCache.read(file, :prism) { ::Prism.parse_file(file).value }
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
def calls(root, line, method_name)
|
|
38
|
+
found = []
|
|
39
|
+
stack = [root]
|
|
40
|
+
until stack.empty?
|
|
41
|
+
node = stack.pop
|
|
42
|
+
found << node if call?(node, line, method_name)
|
|
43
|
+
stack.concat(node.compact_child_nodes)
|
|
44
|
+
end
|
|
45
|
+
found
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
def call?(node, line, method_name)
|
|
49
|
+
node.is_a?(::Prism::CallNode) &&
|
|
50
|
+
node.name.to_sym == method_name &&
|
|
51
|
+
node.message_loc&.start_line == line
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
def receiver_source(node)
|
|
55
|
+
receiver = node.receiver
|
|
56
|
+
return nil unless receiver_nodes.any? { |kls| receiver.is_a?(kls) }
|
|
57
|
+
|
|
58
|
+
receiver.slice
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
def receiver_nodes
|
|
62
|
+
@receiver_nodes ||= RECEIVER_NODE_NAMES.select { |name| ::Prism.const_defined?(name) }
|
|
63
|
+
.map { |name| ::Prism.const_get(name) }
|
|
64
|
+
end
|
|
65
|
+
end
|
|
66
|
+
end
|
|
67
|
+
end
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'typerb/source_cache'
|
|
4
|
+
|
|
5
|
+
module Typerb
|
|
6
|
+
module RubyVmParser
|
|
7
|
+
CALL_TYPES = %i[CALL QCALL].freeze
|
|
8
|
+
RECEIVER_TYPES = %i[LVAR DVAR IVAR CVAR GVAR CONST COLON2 COLON3 CALL QCALL VCALL FCALL ITER].freeze
|
|
9
|
+
|
|
10
|
+
class << self
|
|
11
|
+
def available?
|
|
12
|
+
defined?(::RubyVM::AbstractSyntaxTree) && ::RubyVM::AbstractSyntaxTree.respond_to?(:parse_file)
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def receiver_sources(file, line, method_name)
|
|
16
|
+
calls(root(file), line, method_name).map { |node| receiver_source(file, node) }
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
private
|
|
20
|
+
|
|
21
|
+
def root(file)
|
|
22
|
+
SourceCache.read(file, :ruby_vm) { ::RubyVM::AbstractSyntaxTree.parse_file(file) }
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def calls(root, line, method_name)
|
|
26
|
+
found = []
|
|
27
|
+
stack = [root]
|
|
28
|
+
until stack.empty?
|
|
29
|
+
node = stack.pop
|
|
30
|
+
found << node if call?(node, line, method_name)
|
|
31
|
+
stack.concat(node.children.grep(::RubyVM::AbstractSyntaxTree::Node))
|
|
32
|
+
end
|
|
33
|
+
found
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
def call?(node, line, method_name)
|
|
37
|
+
CALL_TYPES.include?(node.type) &&
|
|
38
|
+
node.children[1] == method_name &&
|
|
39
|
+
(node.first_lineno..node.last_lineno).cover?(line)
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
def receiver_source(file, node)
|
|
43
|
+
receiver = node.children.first
|
|
44
|
+
return nil unless receiver.is_a?(::RubyVM::AbstractSyntaxTree::Node)
|
|
45
|
+
return nil unless RECEIVER_TYPES.include?(receiver.type)
|
|
46
|
+
return nil unless receiver.first_lineno == receiver.last_lineno
|
|
47
|
+
|
|
48
|
+
line = lines(file)[receiver.first_lineno - 1]
|
|
49
|
+
line&.byteslice(receiver.first_column...receiver.last_column) # AST columns are byte offsets
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
def lines(file)
|
|
53
|
+
SourceCache.read(file, :lines) { File.readlines(file) }
|
|
54
|
+
end
|
|
55
|
+
end
|
|
56
|
+
end
|
|
57
|
+
end
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Typerb
|
|
4
|
+
module SourceCache
|
|
5
|
+
LIMIT = 32
|
|
6
|
+
|
|
7
|
+
class << self
|
|
8
|
+
def read(file, kind)
|
|
9
|
+
stat = File.stat(file)
|
|
10
|
+
key = [file, kind, stat.mtime, stat.size]
|
|
11
|
+
mutex.synchronize do
|
|
12
|
+
return store[key] if store.key?(key)
|
|
13
|
+
|
|
14
|
+
store.shift while store.size >= LIMIT
|
|
15
|
+
store[key] = yield
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
private
|
|
20
|
+
|
|
21
|
+
def store
|
|
22
|
+
@store ||= {}
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def mutex
|
|
26
|
+
@mutex ||= Mutex.new
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
end
|
data/lib/typerb/variable_name.rb
CHANGED
|
@@ -1,30 +1,34 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
+
require 'typerb/prism_parser'
|
|
4
|
+
require 'typerb/ruby_vm_parser'
|
|
5
|
+
|
|
3
6
|
module Typerb
|
|
4
7
|
class VariableName
|
|
5
|
-
|
|
8
|
+
BACKENDS = [PrismParser, RubyVmParser].freeze
|
|
9
|
+
|
|
10
|
+
attr_reader :file, :line, :method_name
|
|
6
11
|
|
|
7
|
-
def initialize(
|
|
8
|
-
@file =
|
|
9
|
-
@line =
|
|
12
|
+
def initialize(location, method_name)
|
|
13
|
+
@file = location&.path
|
|
14
|
+
@line = location&.lineno
|
|
15
|
+
@method_name = method_name
|
|
10
16
|
end
|
|
11
17
|
|
|
12
18
|
def get
|
|
13
|
-
return unless
|
|
14
|
-
return unless File.exist?(file)
|
|
19
|
+
return unless backend
|
|
20
|
+
return unless file && line && File.exist?(file)
|
|
15
21
|
|
|
16
|
-
|
|
17
|
-
|
|
22
|
+
receivers = backend.receiver_sources(file, line, method_name)
|
|
23
|
+
receivers.first if receivers.size == 1
|
|
24
|
+
rescue StandardError, ScriptError
|
|
25
|
+
nil
|
|
18
26
|
end
|
|
19
27
|
|
|
20
28
|
private
|
|
21
29
|
|
|
22
|
-
def
|
|
23
|
-
|
|
24
|
-
node = RubyVM::AbstractSyntaxTree.parse(code)
|
|
25
|
-
if node.children.last.children.size == 3 && node.children.last.children[1] == caller_method # rubocop: disable Style/IfUnlessModifier, Style/GuardClause
|
|
26
|
-
node.children.last.children.first.children.first
|
|
27
|
-
end
|
|
30
|
+
def backend
|
|
31
|
+
BACKENDS.find(&:available?)
|
|
28
32
|
end
|
|
29
33
|
end
|
|
30
34
|
end
|
data/lib/typerb/version.rb
CHANGED
data/lib/typerb.rb
CHANGED
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
3
|
require 'typerb/version'
|
|
4
|
-
require 'typerb/variable_name'
|
|
5
4
|
require 'typerb/exceptional'
|
|
6
5
|
|
|
7
6
|
module Typerb
|
|
@@ -10,54 +9,51 @@ module Typerb
|
|
|
10
9
|
raise ArgumentError, 'provide at least one class' if klasses.empty?
|
|
11
10
|
return self if klasses.any? { |kls| is_a?(kls) }
|
|
12
11
|
|
|
13
|
-
klasses_text =
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
"expected #{klasses_text}, got #{self.class} (#{self})"
|
|
18
|
-
end
|
|
19
|
-
|
|
20
|
-
Typerb::Exceptional.new.raise_with(caller, exception_text)
|
|
12
|
+
klasses_text = klasses.join(' or ')
|
|
13
|
+
Typerb::Exceptional.raise_type_error(caller, caller_locations(1, 1)[0], :type!) do |var_name|
|
|
14
|
+
var_name ? "`#{var_name}` should be #{klasses_text}, not #{self.class} (#{self})" : "expected #{klasses_text}, got #{self.class} (#{self})"
|
|
15
|
+
end
|
|
21
16
|
end
|
|
22
17
|
|
|
23
18
|
def not_nil!
|
|
24
|
-
return self unless self.nil? # rubocop: disable Style/RedundantSelf
|
|
25
|
-
|
|
26
|
-
exception_text = if (var_name = Typerb::VariableName.new(caller_locations(1, 1)).get)
|
|
27
|
-
"`#{var_name}` should not be nil"
|
|
28
|
-
else
|
|
29
|
-
'expected not nil, got nil'
|
|
30
|
-
end
|
|
19
|
+
return self unless self.nil? # rubocop: disable Style/RedundantSelf
|
|
31
20
|
|
|
32
|
-
Typerb::Exceptional.
|
|
21
|
+
Typerb::Exceptional.raise_type_error(caller, caller_locations(1, 1)[0], :not_nil!) do |var_name|
|
|
22
|
+
var_name ? "`#{var_name}` should not be nil" : 'expected not nil, got nil'
|
|
23
|
+
end
|
|
33
24
|
end
|
|
34
25
|
|
|
35
26
|
def respond_to!(*methods)
|
|
36
27
|
raise ArgumentError, 'provide at least one method' if methods.empty?
|
|
37
28
|
return self if methods.all? { |meth| respond_to?(meth) }
|
|
38
29
|
|
|
39
|
-
methods_text =
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
"#{self.class} should respond to all methods: #{methods_text}"
|
|
44
|
-
end
|
|
45
|
-
|
|
46
|
-
Typerb::Exceptional.new.raise_with(caller, exception_text)
|
|
30
|
+
methods_text = methods.join(', ')
|
|
31
|
+
Typerb::Exceptional.raise_type_error(caller, caller_locations(1, 1)[0], :respond_to!) do |var_name|
|
|
32
|
+
var_name ? "#{self.class} (`#{var_name}`) should respond to all methods: #{methods_text}" : "#{self.class} should respond to all methods: #{methods_text}"
|
|
33
|
+
end
|
|
47
34
|
end
|
|
48
35
|
|
|
49
36
|
def enum!(*elements)
|
|
50
37
|
raise ArgumentError, 'provide at least one enum element' if elements.empty?
|
|
51
38
|
return self if elements.include?(self)
|
|
52
39
|
|
|
53
|
-
elements_text =
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
40
|
+
elements_text = "[#{elements.join(', ')}]"
|
|
41
|
+
Typerb::Exceptional.raise_type_error(caller, caller_locations(1, 1)[0], :enum!) do |var_name|
|
|
42
|
+
var_name ? "#{self.class} (`#{var_name}`) should be one of: #{elements_text}, not #{self}" : "#{self.class} expected one of: #{elements_text}, got #{self}"
|
|
43
|
+
end
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
def subset_of!(superset)
|
|
47
|
+
raise ArgumentError, 'receiver must be Enumerable' unless is_a?(Enumerable)
|
|
48
|
+
raise ArgumentError, 'superset must be Enumerable' unless superset.is_a?(Enumerable)
|
|
49
|
+
|
|
50
|
+
elements = superset.to_a
|
|
51
|
+
raise ArgumentError, 'provide at least one superset element' if elements.empty?
|
|
52
|
+
return self if (to_a - elements).empty?
|
|
59
53
|
|
|
60
|
-
Typerb::Exceptional.
|
|
54
|
+
Typerb::Exceptional.raise_type_error(caller, caller_locations(1, 1)[0], :subset_of!) do |var_name|
|
|
55
|
+
var_name ? "#{self.class} (`#{var_name}`) should be subset of: #{superset}, not #{self}" : "#{self.class} expected subset of: #{superset}, got #{self}"
|
|
56
|
+
end
|
|
61
57
|
end
|
|
62
58
|
end
|
|
63
59
|
end
|
metadata
CHANGED
|
@@ -1,59 +1,16 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: typerb
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.5.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Oleg Antonyan
|
|
8
|
-
|
|
9
|
-
bindir: exe
|
|
8
|
+
bindir: bin
|
|
10
9
|
cert_chain: []
|
|
11
|
-
date:
|
|
10
|
+
date: 1980-01-02 00:00:00.000000000 Z
|
|
12
11
|
dependencies:
|
|
13
12
|
- !ruby/object:Gem::Dependency
|
|
14
|
-
name:
|
|
15
|
-
requirement: !ruby/object:Gem::Requirement
|
|
16
|
-
requirements:
|
|
17
|
-
- - ">="
|
|
18
|
-
- !ruby/object:Gem::Version
|
|
19
|
-
version: '1.17'
|
|
20
|
-
type: :development
|
|
21
|
-
prerelease: false
|
|
22
|
-
version_requirements: !ruby/object:Gem::Requirement
|
|
23
|
-
requirements:
|
|
24
|
-
- - ">="
|
|
25
|
-
- !ruby/object:Gem::Version
|
|
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'
|
|
55
|
-
- !ruby/object:Gem::Dependency
|
|
56
|
-
name: pry
|
|
13
|
+
name: minitest
|
|
57
14
|
requirement: !ruby/object:Gem::Requirement
|
|
58
15
|
requirements:
|
|
59
16
|
- - ">="
|
|
@@ -68,34 +25,6 @@ dependencies:
|
|
|
68
25
|
version: '0'
|
|
69
26
|
- !ruby/object:Gem::Dependency
|
|
70
27
|
name: rake
|
|
71
|
-
requirement: !ruby/object:Gem::Requirement
|
|
72
|
-
requirements:
|
|
73
|
-
- - ">="
|
|
74
|
-
- !ruby/object:Gem::Version
|
|
75
|
-
version: '10.0'
|
|
76
|
-
type: :development
|
|
77
|
-
prerelease: false
|
|
78
|
-
version_requirements: !ruby/object:Gem::Requirement
|
|
79
|
-
requirements:
|
|
80
|
-
- - ">="
|
|
81
|
-
- !ruby/object:Gem::Version
|
|
82
|
-
version: '10.0'
|
|
83
|
-
- !ruby/object:Gem::Dependency
|
|
84
|
-
name: rspec
|
|
85
|
-
requirement: !ruby/object:Gem::Requirement
|
|
86
|
-
requirements:
|
|
87
|
-
- - ">="
|
|
88
|
-
- !ruby/object:Gem::Version
|
|
89
|
-
version: '3.0'
|
|
90
|
-
type: :development
|
|
91
|
-
prerelease: false
|
|
92
|
-
version_requirements: !ruby/object:Gem::Requirement
|
|
93
|
-
requirements:
|
|
94
|
-
- - ">="
|
|
95
|
-
- !ruby/object:Gem::Version
|
|
96
|
-
version: '3.0'
|
|
97
|
-
- !ruby/object:Gem::Dependency
|
|
98
|
-
name: rubocop
|
|
99
28
|
requirement: !ruby/object:Gem::Requirement
|
|
100
29
|
requirements:
|
|
101
30
|
- - ">="
|
|
@@ -109,7 +38,7 @@ dependencies:
|
|
|
109
38
|
- !ruby/object:Gem::Version
|
|
110
39
|
version: '0'
|
|
111
40
|
- !ruby/object:Gem::Dependency
|
|
112
|
-
name:
|
|
41
|
+
name: rubocop
|
|
113
42
|
requirement: !ruby/object:Gem::Requirement
|
|
114
43
|
requirements:
|
|
115
44
|
- - ">="
|
|
@@ -122,37 +51,33 @@ dependencies:
|
|
|
122
51
|
- - ">="
|
|
123
52
|
- !ruby/object:Gem::Version
|
|
124
53
|
version: '0'
|
|
125
|
-
description:
|
|
54
|
+
description: Refinement adding type!, not_nil!, respond_to!, enum! and subset_of!
|
|
55
|
+
assertions that name the variable they failed on.
|
|
126
56
|
email:
|
|
127
57
|
- oleg.b.antonyan@gmail.com
|
|
128
58
|
executables: []
|
|
129
59
|
extensions: []
|
|
130
60
|
extra_rdoc_files: []
|
|
131
61
|
files:
|
|
132
|
-
-
|
|
133
|
-
- ".rspec"
|
|
134
|
-
- ".rubocop.yml"
|
|
135
|
-
- ".ruby-version"
|
|
136
|
-
- ".travis.yml"
|
|
62
|
+
- CHANGELOG.md
|
|
137
63
|
- CODE_OF_CONDUCT.md
|
|
138
|
-
- Gemfile
|
|
139
|
-
- Gemfile.lock
|
|
140
|
-
- Guardfile
|
|
141
64
|
- LICENSE.txt
|
|
142
65
|
- README.md
|
|
143
|
-
- Rakefile
|
|
144
|
-
- bin/console
|
|
145
|
-
- bin/setup
|
|
146
66
|
- lib/typerb.rb
|
|
147
67
|
- lib/typerb/exceptional.rb
|
|
68
|
+
- lib/typerb/prism_parser.rb
|
|
69
|
+
- lib/typerb/ruby_vm_parser.rb
|
|
70
|
+
- lib/typerb/source_cache.rb
|
|
148
71
|
- lib/typerb/variable_name.rb
|
|
149
72
|
- lib/typerb/version.rb
|
|
150
|
-
- typerb.gemspec
|
|
151
73
|
homepage: https://github.com/olegantonyan/typerb
|
|
152
74
|
licenses:
|
|
153
75
|
- MIT
|
|
154
|
-
metadata:
|
|
155
|
-
|
|
76
|
+
metadata:
|
|
77
|
+
source_code_uri: https://github.com/olegantonyan/typerb
|
|
78
|
+
changelog_uri: https://github.com/olegantonyan/typerb/blob/master/CHANGELOG.md
|
|
79
|
+
bug_tracker_uri: https://github.com/olegantonyan/typerb/issues
|
|
80
|
+
rubygems_mfa_required: 'true'
|
|
156
81
|
rdoc_options: []
|
|
157
82
|
require_paths:
|
|
158
83
|
- lib
|
|
@@ -160,15 +85,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
|
160
85
|
requirements:
|
|
161
86
|
- - ">="
|
|
162
87
|
- !ruby/object:Gem::Version
|
|
163
|
-
version: '
|
|
88
|
+
version: '3.0'
|
|
164
89
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
165
90
|
requirements:
|
|
166
91
|
- - ">="
|
|
167
92
|
- !ruby/object:Gem::Version
|
|
168
93
|
version: '0'
|
|
169
94
|
requirements: []
|
|
170
|
-
rubygems_version:
|
|
171
|
-
signing_key:
|
|
95
|
+
rubygems_version: 4.0.16
|
|
172
96
|
specification_version: 4
|
|
173
97
|
summary: Typecheck sugar for Ruby.
|
|
174
98
|
test_files: []
|
data/.gitignore
DELETED
data/.rspec
DELETED
data/.rubocop.yml
DELETED
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
AllCops:
|
|
2
|
-
TargetRubyVersion: 2.4
|
|
3
|
-
Exclude:
|
|
4
|
-
- 'bin/**/*'
|
|
5
|
-
- 'Guardfile'
|
|
6
|
-
|
|
7
|
-
inherit_mode:
|
|
8
|
-
merge:
|
|
9
|
-
- Exclude
|
|
10
|
-
|
|
11
|
-
Style/CommentedKeyword:
|
|
12
|
-
Enabled: false
|
|
13
|
-
|
|
14
|
-
Style/Documentation:
|
|
15
|
-
Enabled: false
|
|
16
|
-
|
|
17
|
-
Style/Semicolon:
|
|
18
|
-
Enabled: false
|
|
19
|
-
|
|
20
|
-
Metrics/LineLength:
|
|
21
|
-
Max: 170
|
data/.ruby-version
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
2.6.6
|
data/.travis.yml
DELETED
data/Gemfile
DELETED
data/Gemfile.lock
DELETED
|
@@ -1,94 +0,0 @@
|
|
|
1
|
-
PATH
|
|
2
|
-
remote: .
|
|
3
|
-
specs:
|
|
4
|
-
typerb (0.3.0)
|
|
5
|
-
|
|
6
|
-
GEM
|
|
7
|
-
remote: https://rubygems.org/
|
|
8
|
-
specs:
|
|
9
|
-
ast (2.4.0)
|
|
10
|
-
awesome_print (1.8.0)
|
|
11
|
-
coderay (1.1.2)
|
|
12
|
-
diff-lcs (1.3)
|
|
13
|
-
ffi (1.11.1)
|
|
14
|
-
formatador (0.2.5)
|
|
15
|
-
guard (2.15.0)
|
|
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)
|
|
29
|
-
jaro_winkler (1.5.3)
|
|
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)
|
|
35
|
-
method_source (0.9.2)
|
|
36
|
-
nenv (0.3.0)
|
|
37
|
-
notiffany (0.1.1)
|
|
38
|
-
nenv (~> 0.1)
|
|
39
|
-
shellany (~> 0.0)
|
|
40
|
-
parallel (1.17.0)
|
|
41
|
-
parser (2.6.3.0)
|
|
42
|
-
ast (~> 2.4.0)
|
|
43
|
-
pry (0.12.2)
|
|
44
|
-
coderay (~> 1.1.0)
|
|
45
|
-
method_source (~> 0.9.0)
|
|
46
|
-
rainbow (3.0.0)
|
|
47
|
-
rake (12.3.2)
|
|
48
|
-
rb-fsevent (0.10.3)
|
|
49
|
-
rb-inotify (0.10.0)
|
|
50
|
-
ffi (~> 1.0)
|
|
51
|
-
rspec (3.8.0)
|
|
52
|
-
rspec-core (~> 3.8.0)
|
|
53
|
-
rspec-expectations (~> 3.8.0)
|
|
54
|
-
rspec-mocks (~> 3.8.0)
|
|
55
|
-
rspec-core (3.8.1)
|
|
56
|
-
rspec-support (~> 3.8.0)
|
|
57
|
-
rspec-expectations (3.8.4)
|
|
58
|
-
diff-lcs (>= 1.2.0, < 2.0)
|
|
59
|
-
rspec-support (~> 3.8.0)
|
|
60
|
-
rspec-mocks (3.8.1)
|
|
61
|
-
diff-lcs (>= 1.2.0, < 2.0)
|
|
62
|
-
rspec-support (~> 3.8.0)
|
|
63
|
-
rspec-support (3.8.2)
|
|
64
|
-
rubocop (0.72.0)
|
|
65
|
-
jaro_winkler (~> 1.5.1)
|
|
66
|
-
parallel (~> 1.10)
|
|
67
|
-
parser (>= 2.6)
|
|
68
|
-
rainbow (>= 2.2.2, < 4.0)
|
|
69
|
-
ruby-progressbar (~> 1.7)
|
|
70
|
-
unicode-display_width (>= 1.4.0, < 1.7)
|
|
71
|
-
ruby-progressbar (1.10.1)
|
|
72
|
-
ruby_dep (1.5.0)
|
|
73
|
-
shellany (0.0.1)
|
|
74
|
-
super_awesome_print (0.2.5)
|
|
75
|
-
awesome_print
|
|
76
|
-
thor (0.20.3)
|
|
77
|
-
unicode-display_width (1.6.0)
|
|
78
|
-
|
|
79
|
-
PLATFORMS
|
|
80
|
-
ruby
|
|
81
|
-
|
|
82
|
-
DEPENDENCIES
|
|
83
|
-
bundler (>= 1.17)
|
|
84
|
-
guard
|
|
85
|
-
guard-rspec
|
|
86
|
-
pry
|
|
87
|
-
rake (>= 10.0)
|
|
88
|
-
rspec (>= 3.0)
|
|
89
|
-
rubocop
|
|
90
|
-
super_awesome_print
|
|
91
|
-
typerb!
|
|
92
|
-
|
|
93
|
-
BUNDLED WITH
|
|
94
|
-
1.17.2
|
data/Guardfile
DELETED
|
@@ -1,36 +0,0 @@
|
|
|
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/Rakefile
DELETED
data/bin/console
DELETED
|
@@ -1,14 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env ruby
|
|
2
|
-
|
|
3
|
-
require 'bundler/setup'
|
|
4
|
-
require 'typerb'
|
|
5
|
-
|
|
6
|
-
# You can add fixtures and/or initialization code here to make experimenting
|
|
7
|
-
# with your gem easier. You can also use a different console, if you like.
|
|
8
|
-
|
|
9
|
-
# (If you use this, don't forget to add pry to your Gemfile!)
|
|
10
|
-
require 'pry'
|
|
11
|
-
Pry.start
|
|
12
|
-
|
|
13
|
-
# require "irb"
|
|
14
|
-
# IRB.start(__FILE__)
|
data/bin/setup
DELETED
data/typerb.gemspec
DELETED
|
@@ -1,37 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
lib = File.expand_path('lib', __dir__)
|
|
4
|
-
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
|
5
|
-
require 'typerb/version'
|
|
6
|
-
|
|
7
|
-
Gem::Specification.new do |spec|
|
|
8
|
-
spec.name = 'typerb'
|
|
9
|
-
spec.version = Typerb::VERSION
|
|
10
|
-
spec.authors = ['Oleg Antonyan']
|
|
11
|
-
spec.email = ['oleg.b.antonyan@gmail.com']
|
|
12
|
-
|
|
13
|
-
spec.summary = 'Typecheck sugar for Ruby.'
|
|
14
|
-
spec.description = 'Typecheck sugar for Ruby.'
|
|
15
|
-
spec.homepage = 'https://github.com/olegantonyan/typerb'
|
|
16
|
-
spec.license = 'MIT'
|
|
17
|
-
|
|
18
|
-
# Specify which files should be added to the gem when it is released.
|
|
19
|
-
# The `git ls-files -z` loads the files in the RubyGem that have been added into git.
|
|
20
|
-
spec.files = Dir.chdir(File.expand_path(__dir__)) do
|
|
21
|
-
`git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
|
|
22
|
-
end
|
|
23
|
-
spec.bindir = 'exe'
|
|
24
|
-
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
|
25
|
-
spec.require_paths = ['lib']
|
|
26
|
-
|
|
27
|
-
spec.add_development_dependency 'bundler', '>= 1.17'
|
|
28
|
-
spec.add_development_dependency 'guard'
|
|
29
|
-
spec.add_development_dependency 'guard-rspec'
|
|
30
|
-
spec.add_development_dependency 'pry'
|
|
31
|
-
spec.add_development_dependency 'rake', '>= 10.0'
|
|
32
|
-
spec.add_development_dependency 'rspec', '>= 3.0'
|
|
33
|
-
spec.add_development_dependency 'rubocop'
|
|
34
|
-
spec.add_development_dependency 'super_awesome_print'
|
|
35
|
-
|
|
36
|
-
spec.required_ruby_version = '>= 2.4'
|
|
37
|
-
end
|