forked from djberg96/interface
-
Notifications
You must be signed in to change notification settings - Fork 2
/
demo.rb
94 lines (79 loc) · 2.58 KB
/
demo.rb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
# run as `RUBY_CUBE_TYPECHECK= 1 ruby examples/demo.rb`
#require_relative '../lib/cube'
require 'cube'
require 'dry-types'
module Types
include Dry::Types.module
end
Adder = Cube.interface {
# sum is a method that takes an array of Types::Strict::Int and returns an Types::Strict::Int
proto(:sum, [Types::Strict::Int]) { Types::Strict::Int }
}
Calculator = Cube.interface {
# interfaces can be composed
extends Adder
# method fact takes an Types::Strict::Int and returns an Types::Strict::Int
proto(:fact, Types::Strict::Int) { Types::Strict::Int }
# method pos takes an array of Types::Strict::Ints, an Types::Strict::Int, and returns either Types::Strict::Int or nil
proto(:pos, [Types::Strict::Array], Types::Strict::Int) { Types::Strict::Int|Types::Strict::Nil }
}
class SimpleCalcImpl
def fact(n)
(2..n).reduce(1) { |m, e| m * e }
end
def sum(a)
a.reduce(0, &:+)
end
def pos(arr, i)
arr.index(i)
end
end
SimpleCalc = Cube[SimpleCalcImpl].as_interface(Calculator)
# OR
# SimpleCalc = Cube.from(SimpleCalcImpl).as_interface(Calculator)
c = SimpleCalc.new
p c.sum([1, 2])
p c.pos([1, 2, 3], 4)
AdvancedCalculator = Cube.interface {
extend Calculator
proto(:product, Types::Strict::Int, Types::Strict::Int) { Types::Strict::Int }
proto(:avg, [Types::Strict::Int]) { Types::Strict::Float }
}
ProductCalcT = Cube.trait do
def product(a, b)
ret = 0
a.times { ret = sum([ret, b]) }
ret
end
# This specifies the interface that the including Class must satisfy in order for
# this trait to work properly.
# Eg, the product method above uses `sum`, which it expects to get from the including
# class
requires_interface Adder # Note that this will give an error if SimpleCalc#sum is removed
# even if this trait itself has a `sum` method
end
StatsCalcT = Cube.trait do
def product; end
def avg(arr)
arr.reduce(0, &:+) / arr.size
end
end
#
# This is how we compose behaviours
# AdvancedCalc is a class which mixes traits AdvancedCalcT and DummyCalcT
# into SimpleCalc and implements the interface AdvancedCalculator
# To avoid conflicts, alias methods in AdvancedCalcT (otherwise error will be raised)
# One can also suppress methods in DummyCalcT
AdvancedCalc = SimpleCalc.with_trait(ProductCalcT)
.with_trait(StatsCalcT, suppress: [:product])
.as_interface(AdvancedCalculator)
sc = AdvancedCalc.new
p sc.product(3, 2)
__END__
# Benchmarks. Run with RUBY_INTERFACE_TYPECHECK=0 and 1 to compare
t1 = Time.now
1_000_000.times do
c.fact(50)
end
t2 = Time.now
p t2 - t1