typo_safe 0.0.1 → 0.0.2
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.
- data/README.md +40 -5
- data/lib/typo_safe.rb +32 -0
- data/lib/typo_safe/version.rb +1 -1
- data/test/test_typo_safe.rb +54 -0
- metadata +6 -3
data/README.md
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
# TypoSafe
|
2
2
|
|
3
|
-
Protect your Ruby code from typos!
|
3
|
+
Protect your Ruby code from typos! You've heard of Type Safe languages, well now Ruby can be Typo Safe! Typo Safe code will revolutionise programming.
|
4
4
|
|
5
5
|
## Installation
|
6
6
|
|
@@ -18,12 +18,47 @@ Or install it yourself as:
|
|
18
18
|
|
19
19
|
## Usage
|
20
20
|
|
21
|
-
|
21
|
+
I'm pretty sure you don't ever want to use this gem, not even in development.
|
22
|
+
|
23
|
+
# Typo Safe a single class written by a fat-fingered developer:
|
24
|
+
|
25
|
+
```ruby
|
26
|
+
require 'typo_safe'
|
27
|
+
|
28
|
+
class SomeClass
|
29
|
+
include TypoSafe
|
30
|
+
|
31
|
+
def print_hell0
|
32
|
+
puts "hello from the print_hello method!"
|
33
|
+
end
|
34
|
+
|
35
|
+
def print_goodbye
|
36
|
+
puts "goodbye from the print_goodbye method!"
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
SomeClass.new.print_hello
|
41
|
+
SomeClass.new.pring_goodbye
|
42
|
+
```
|
43
|
+
|
44
|
+
## Why?!
|
45
|
+
|
46
|
+
A discussion in Campfire:
|
47
|
+
|
48
|
+

|
22
49
|
|
23
50
|
## Contributing
|
24
51
|
|
25
52
|
1. Fork it
|
26
53
|
2. Create your feature branch (`git checkout -b my-new-feature`)
|
27
|
-
3.
|
28
|
-
4.
|
29
|
-
5.
|
54
|
+
3. Write, then test your changes (`rake test`)
|
55
|
+
4. Commit your changes (`git commit -am 'Add some feature'`)
|
56
|
+
5. Push to the branch (`git push origin my-new-feature`)
|
57
|
+
6. Create new Pull Request
|
58
|
+
|
59
|
+
## TODO
|
60
|
+
|
61
|
+
* Make the gem respect public/private methods (at the moment you can call a private method by using a typo)
|
62
|
+
* Benchmark Levenshtein calculations and possibly cache
|
63
|
+
* At the moment when there is a conflict (two methods have the same Levenshtein distance) the first is picked, maybe favour locally defined methods over inherited methods
|
64
|
+
* Make including TypoSafe on Object work (for global protection!)
|
data/lib/typo_safe.rb
ADDED
@@ -0,0 +1,32 @@
|
|
1
|
+
require "typo_safe/version"
|
2
|
+
require 'text'
|
3
|
+
|
4
|
+
module TypoSafe
|
5
|
+
@@maximum_levenshtein_distance_for_match = 4
|
6
|
+
|
7
|
+
def method_missing(requested_method, *args, &block)
|
8
|
+
distances = []
|
9
|
+
methods.select{ |m|
|
10
|
+
a = method(m).arity
|
11
|
+
(a >= 0 && a == args.size) || (a < 0 && (0 - a - 1) <= args.size)
|
12
|
+
}.each { |meth|
|
13
|
+
distance = Text::Levenshtein.distance(requested_method.to_s, meth.to_s)
|
14
|
+
distances << {meth: meth, dist: Text::Levenshtein.distance(requested_method.to_s, meth.to_s)} if distance <= @@maximum_levenshtein_distance_for_match
|
15
|
+
}
|
16
|
+
|
17
|
+
if distances.size == 0
|
18
|
+
super
|
19
|
+
else
|
20
|
+
closest_match = distances.sort_by{|dist| dist[:dist]}.first
|
21
|
+
if block_given?
|
22
|
+
send(closest_match[:meth], *args, &block)
|
23
|
+
else
|
24
|
+
send(closest_match[:meth], *args)
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
def self.maximum_levenshtein_distance_for_match=(val)
|
30
|
+
@@maximum_levenshtein_distance_for_match = val
|
31
|
+
end
|
32
|
+
end
|
data/lib/typo_safe/version.rb
CHANGED
@@ -0,0 +1,54 @@
|
|
1
|
+
require 'minitest/autorun'
|
2
|
+
$:.unshift File.join(File.dirname(__FILE__), '..')
|
3
|
+
require 'typo_safe'
|
4
|
+
|
5
|
+
class TestTypoSafe < MiniTest::Unit::TestCase
|
6
|
+
def setup
|
7
|
+
@foo = Class.new do
|
8
|
+
include TypoSafe
|
9
|
+
def tset; true; end
|
10
|
+
def xxxxxxxxxx; true; end
|
11
|
+
def aaaaaaaaaa(an_obj, str); yield(an_obj, str); end
|
12
|
+
def bbbbbbbbbb(an_obj, str); an_obj.ping(str); end
|
13
|
+
def cccccccccc; end
|
14
|
+
def ccccccccbb(an_arg); end
|
15
|
+
|
16
|
+
# Methods for test_ignores_methods_that_are_not_arg_or_block_campatible
|
17
|
+
def arity_test_aaaaaaa(arg, other_arg); "aaaaaaa"; end
|
18
|
+
def arity_test_aaaaaab(arg); "aaaaaab"; end
|
19
|
+
end.new
|
20
|
+
end
|
21
|
+
|
22
|
+
def test_typo_method_dispatch
|
23
|
+
assert @foo.test
|
24
|
+
end
|
25
|
+
|
26
|
+
def test_passes_args_and_no_block
|
27
|
+
tbc = MiniTest::Mock.new
|
28
|
+
tbc.expect :ping, true, ["foo"]
|
29
|
+
@foo.bbbbbbbbba(tbc, "foo")
|
30
|
+
assert tbc.verify
|
31
|
+
end
|
32
|
+
|
33
|
+
def test_passes_args_and_block
|
34
|
+
tbc = MiniTest::Mock.new
|
35
|
+
tbc.expect :ping, true, ["foo"]
|
36
|
+
@foo.aaaaaaaaab(tbc, "foo") {|obj, arg| obj.ping(arg)}
|
37
|
+
assert tbc.verify
|
38
|
+
end
|
39
|
+
|
40
|
+
def test_requires_minimum_similarity
|
41
|
+
error = assert_raises(NoMethodError) {@foo.kdygfnkudfjh}
|
42
|
+
assert error.message.match /undefined method `kdygfnkudfjh' for #<#<Class/
|
43
|
+
end
|
44
|
+
|
45
|
+
def test_setting_minimum_similarity
|
46
|
+
TypoSafe::maximum_levenshtein_distance_for_match = 2
|
47
|
+
assert_raises(NoMethodError) {@foo.xxxxxxxyyy}
|
48
|
+
end
|
49
|
+
|
50
|
+
def test_ignores_methods_that_are_not_arg_or_block_campatible
|
51
|
+
assert_equal @foo.arity_test_aaaaaax(1, 2), "aaaaaaa"
|
52
|
+
assert_equal @foo.arity_test_aaaaaax(1), "aaaaaab"
|
53
|
+
end
|
54
|
+
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: typo_safe
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.2
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2013-01-
|
12
|
+
date: 2013-01-12 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: text
|
@@ -39,7 +39,9 @@ files:
|
|
39
39
|
- LICENSE.txt
|
40
40
|
- README.md
|
41
41
|
- Rakefile
|
42
|
+
- lib/typo_safe.rb
|
42
43
|
- lib/typo_safe/version.rb
|
44
|
+
- test/test_typo_safe.rb
|
43
45
|
- typo_safe.gemspec
|
44
46
|
homepage: ''
|
45
47
|
licenses: []
|
@@ -65,4 +67,5 @@ rubygems_version: 1.8.24
|
|
65
67
|
signing_key:
|
66
68
|
specification_version: 3
|
67
69
|
summary: You probably don't really want to use this in production. Or ever.
|
68
|
-
test_files:
|
70
|
+
test_files:
|
71
|
+
- test/test_typo_safe.rb
|