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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 1ce9f42a58f215a179f850016e0f647a4e16b4f23b3021d7cd17a43960857439
4
- data.tar.gz: 9bb4dc2cb1f2396c7ccfd773d27a2d85e0d11f3a66ef54537e9c809594795d5a
3
+ metadata.gz: f7cef67daf67692e132e69a417bc8d7ea8162c56e87f7c058b5d095aed720506
4
+ data.tar.gz: 8493a01a0310fe1accb703ee82515b8f59163dc4069117774df00fafd0228113
5
5
  SHA512:
6
- metadata.gz: a35899b9f7f7cc045725241d6eef0d312470016e2945edea86c67696c67f3ba69bbc52743fd51cb0253b6b7bc4f3be30ac9567784269a6f382d46484b9bc2476
7
- data.tar.gz: 58c8a8839809ff2c87801388cca35dca300a565616645a01d9bd59fdea6e6986c74763250093400aaca8d2b91a47cfad8b24b0060b24ae0215a3bdb846617568
6
+ metadata.gz: e69f6c28e078a84bded21be966969c7979ab71f26dff4379b7952026c3ea180422ac68ae82b4e2ef003cd34cb47fd0902f474024758ff756984aaa0f937a7eae
7
+ data.tar.gz: f5ea90611dbd4429a48b11b59ce69d2e6f4e267e7d451916171bb06f680e64f6bec033f1f31dd7c6c6096f510123d1dc2b0aa50932630c0ec6406022bb81e2e9
data/.gitignore CHANGED
@@ -6,6 +6,7 @@
6
6
  /pkg/
7
7
  /spec/reports/
8
8
  /tmp/
9
+ /vendor/
9
10
  *.gem
10
11
 
11
12
  # rspec failure tracking
data/.rubocop.yml CHANGED
@@ -2,6 +2,7 @@ AllCops:
2
2
  TargetRubyVersion: 2.4
3
3
  Exclude:
4
4
  - 'bin/**/*'
5
+ - 'Guardfile'
5
6
 
6
7
  inherit_mode:
7
8
  merge:
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- typerb (0.1.6)
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!()` method to `Object` class so you can call it on almost much any object (except those inherited from `BasicObject`, but these are rare).
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
- It requires Ruby 2.6.0-preview3. Relies on `RubyVM::AST` which may change in release version. So, expect breaking changes in Ruby.
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) # 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
111
- # some_arg. type!(String) is ok though
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 # here we cannot get the source code for a line containing "a.type!(Hash)", so cannot see the variable name
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) # no way to tell the variable - raise error message without variable name
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
  ```
@@ -6,6 +6,10 @@ module Typerb
6
6
  def klasses_text(klasses)
7
7
  klasses.size > 1 ? klasses.map(&:name).join(' or ') : klasses.first.name
8
8
  end
9
+
10
+ def methods_text(methods)
11
+ methods.join(', ')
12
+ end
9
13
  end
10
14
 
11
15
  def raise_with(backtrace, exception_text)
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Typerb
4
- VERSION = '0.1.6'
4
+ VERSION = '0.1.7'
5
5
  end
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.6
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-13 00:00:00.000000000 Z
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