README.md in rubype-0.2.4 vs README.md in rubype-0.2.5

- old
+ new

@@ -1,9 +1,10 @@ # Ruby + Type = Rubype [![Gem Version](https://badge.fury.io/rb/rubype.svg)](http://badge.fury.io/rb/rubype) [![Build Status](https://travis-ci.org/gogotanaka/Rubype.svg?branch=develop)](https://travis-ci.org/gogotanaka/Rubype) [![Dependency Status](https://gemnasium.com/gogotanaka/Rubype.svg)](https://gemnasium.com/gogotanaka/Rubype) [![Code Climate](https://codeclimate.com/github/gogotanaka/Rubype/badges/gpa.svg)](https://codeclimate.com/github/gogotanaka/Rubype) +![210414.png](https://qiita-image-store.s3.amazonaws.com/0/30440/0aafba03-1a4c-4676-5377-75f906aaeab9.png) ```rb # Assert class of both args is Numeric and class of return is String def sum(x, y) (x + y).to_s end @@ -17,15 +18,26 @@ ``` This gem brings you advantage of type without changing existing code's behavior. +## Good point: +* Meaningful error +* Executable documentation +* Don't need to check type of method's arguments and return. +* Type info itself is object, you can check it and even change it during run time. + +## Bad point: +* Checking type run every time method call... it might be overhead, but it's not big deal. +* There is no static analysis. + # Feature ### Advantage of type * Meaningful error * Executable documentation +* Don't need to check type of method's arguments and return . ```rb require 'rubype' # ex1: Assert class of args and return @@ -43,11 +55,11 @@ MyClass.new.sum(1, 2) #=> 3 MyClass.new.sum(1, 'string') -#=> Rubype::ArgumentTypeError: Expected MyClass#sum's 2th argument to be Numeric but got "string" instead +#=> Rubype::ArgumentTypeError: Expected MyClass#sum's 2nd argument to be Numeric but got "string" instead MyClass.new.wrong_sum(1, 2) #=> Rubype::ReturnTypeError: Expected MyClass#wrong_sum to return Numeric but got "string" instead @@ -61,11 +73,11 @@ MyClass.new.sum('1', 2) #=> 3 MyClass.new.sum(:has_no_to_i, 2) -#=> Rubype::ArgumentTypeError: Expected MyClass#sum's 1th argument to have method #to_i but got :has_no_to_i instead +#=> Rubype::ArgumentTypeError: Expected MyClass#sum's 1st argument to have method #to_i but got :has_no_to_i instead # ex3: You can use Any class, if you want class People def marry(people) @@ -76,11 +88,11 @@ People.new.marry(People.new) #=> no error People.new.marry('non people') -#=> Rubype::ArgumentTypeError: Expected People#marry's 1th argument to be People but got "non people" instead +#=> Rubype::ArgumentTypeError: Expected People#marry's 1st argument to be People but got "non people" instead ``` ### Typed method can coexist with non-typed method @@ -88,11 +100,11 @@ # It's totally OK!! class MyClass def method_with_type(x, y) x + y end - typesig :sum, [Numeric, Numeric] => Numeric + typesig :method_with_type, [Numeric, Numeric] => Numeric def method_without_type(x, y) 'string' end end @@ -132,19 +144,85 @@ x.to_i + y end typesig :sum, [:to_i, Numeric] => Numeric end -MyClass.new.method(:foo).type_info +MyClass.new.method(:sum).type_info # => [:to_i, Numeric] => Numeric +MyClass.new.method(:sum).arg_types +# => [:to_i, Numeric] + +MyClass.new.method(:sum).return_type +# => Numeric + ``` +## Benchmarks + +```ruby +require 'rubype' +require 'benchmark' + +class RubypeCommonClass + def sum(x, y) + x + y + end + typesig :sum, [Numeric, Numeric] => Numeric +end + +class CommonClass + def sum(x, y) + x + y + end +end + +class RubypeDucktypeClass + def sum(x, y) + x.to_i + y + end + typesig :sum, [:to_i, Numeric] => Numeric +end + +class DucktypeClass + def sum(x, y) + x.to_i + y + end +end + +N = 100_000 +Benchmark.bm("RubypeDucktypeClass".length + 3) do |x| + x.report("RubypeCommonClass") { N.times { RubypeCommonClass.new.sum(1, 5) } } + x.report("CommonClass") { N.times { CommonClass.new.sum(1, 5) } } +end + +Benchmark.bm("RubypeDucktypeClass".length + 3) do |x| + x.report("RubypeDucktypeClass") { N.times { RubypeDucktypeClass.new.sum(1, 5) } } + x.report("DucktypeClass") { N.times { DucktypeClass.new.sum(1, 5) } } +end +``` + +### Results +Ruby 2.2.0, Macbook Pro 2.9Ghz Intel Core i7, 8GB RAM + +``` + user system total real +RubypeCommonClass 0.530000 0.010000 0.540000 ( 0.566493) +CommonClass 0.030000 0.000000 0.030000 ( 0.035718) + user system total real +RubypeDucktypeClass 0.590000 0.010000 0.600000 ( 0.682504) +DucktypeClass 0.030000 0.000000 0.030000 ( 0.029856) +``` + + + ## Installation gem install rubype or add gem 'rubype' to your Gemfile. +And `require 'rubype'`, enjoy typed Ruby. + This gem requires Ruby 2.0.0+. ### Contributing Fork it ( https://github.com/[my-github-username]/rubype/fork ) @@ -159,10 +237,10 @@ ...... Finished in 0.010961s, 547.3953 runs/s, 5017.7903 assertions/s. - 6 runs, 55 assertions, 0 failures, 0 errors, 0 skips + 7 runs, 61 assertions, 0 failures, 0 errors, 0 skips Push to the branch (`git push origin my-new-feature`) Create a new Pull Request to `develop` branch