tiny_frp 0.0.3 → 1.0.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/lib/tiny_frp/version.rb +1 -1
- data/lib/tiny_frp.rb +81 -104
- data/unit_test/test_tiny_frp.rb +23 -61
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 95461bc9e9bcaec52bd9d693befbab7f761c4596
|
4
|
+
data.tar.gz: 864a0e822365a039c315192d02c509b8a15ddeef
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 68ee1322327823da24345bbd919030bec4e33990d2379612c1d3efa09d982215c73c39d4171489edda8786a90aa22a4c29334e64e7220fbdd9b47fbf6e64e719
|
7
|
+
data.tar.gz: 34f5f5cdd816f06c61a22a07ff5625d24b43370a0784e48127d4b281bef255cebb18dceb478e1e66f41f611508ed2a8586145921632e772e0a16402b4e241344
|
data/lib/tiny_frp/version.rb
CHANGED
data/lib/tiny_frp.rb
CHANGED
@@ -1,144 +1,121 @@
|
|
1
1
|
require "tiny_frp/version"
|
2
2
|
|
3
3
|
module TinyFRP
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
4
|
+
def self.process(node, n)
|
5
|
+
n.times.inject(res: [], last_memo: {}){|acc|
|
6
|
+
memo = node.call({}, acc[:last_memo])
|
7
|
+
{res: acc[:res] + [memo[node]], last_memo: memo}
|
8
|
+
}[:res]
|
9
|
+
end
|
10
10
|
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
11
|
+
def self.loop(node, &proc)
|
12
|
+
last_memo = {}
|
13
|
+
loop {
|
14
|
+
memo = node.call({}, last_memo)
|
15
|
+
proc.call(*memo[node])
|
16
|
+
last_memo = memo
|
17
|
+
}
|
18
|
+
end
|
19
|
+
|
20
|
+
class Node
|
21
|
+
def >>(node)
|
22
|
+
Composite.new(self, node)
|
15
23
|
end
|
16
24
|
|
17
|
-
def
|
18
|
-
|
19
|
-
s, i = *a
|
20
|
-
edges = traverse(s).merge(s.node => [[i, signal.node]]){|k, old, new| (old + new).uniq}
|
21
|
-
h.merge(edges){|k, old, new| (old + new).uniq}
|
22
|
-
end
|
25
|
+
def <<(node)
|
26
|
+
Composite.new(node, self)
|
23
27
|
end
|
24
28
|
|
25
|
-
def
|
26
|
-
|
27
|
-
queue = Array.new(@inputs)
|
28
|
-
until queue.empty?
|
29
|
-
node = queue.shift
|
30
|
-
val = node.call(*received[node].sort{|a, b| a[0] <=> b[0]}.map{|idx, val| val})
|
31
|
-
@children[node].each do |idx, ch_node|
|
32
|
-
received[ch_node] = received[ch_node] + [[idx, val]]
|
33
|
-
if received[ch_node].size == @parents[ch_node].size
|
34
|
-
queue << ch_node
|
35
|
-
end
|
36
|
-
end
|
37
|
-
end
|
38
|
-
return val
|
29
|
+
def +(node)
|
30
|
+
Bundle.new(self, node)
|
39
31
|
end
|
40
32
|
|
41
|
-
def
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
proc.call(v) if proc
|
47
|
-
}
|
48
|
-
when 0
|
49
|
-
[]
|
50
|
-
when 1
|
51
|
-
[conduct]
|
52
|
-
when Integer
|
53
|
-
[conduct] + run(mode - 1)
|
33
|
+
def call(memo, last_memo, *args)
|
34
|
+
if memo.has_key?(self)
|
35
|
+
memo
|
36
|
+
else
|
37
|
+
calc(memo, last_memo, *args)
|
54
38
|
end
|
55
39
|
end
|
56
40
|
end
|
57
41
|
|
58
|
-
class
|
59
|
-
|
60
|
-
|
61
|
-
@node, @assigned_signals = node, assigned_signals
|
42
|
+
class Lift < Node
|
43
|
+
def initialize(&proc)
|
44
|
+
@proc = proc
|
62
45
|
end
|
63
|
-
end
|
64
|
-
|
65
|
-
class Node
|
66
|
-
attr_reader :fixed_argc
|
67
46
|
|
68
|
-
def
|
69
|
-
|
47
|
+
def argc
|
48
|
+
@argc ||= @proc.parameters.select{|t, n| t == :opt}.count
|
70
49
|
end
|
71
50
|
|
72
|
-
def
|
73
|
-
|
74
|
-
if signals.any?{|s| !s.is_a?(Signal)}
|
75
|
-
raise "Error: cannot apply SignalFunction to Non-Signal Object."
|
76
|
-
end
|
77
|
-
if signals.size < @fixed_argc || (!@rest_arg && signals.size != @fixed_argc)
|
78
|
-
raise "Error: cannot apply SignalFunction to Signals."
|
79
|
-
end
|
80
|
-
Signal.new(self, signals)
|
51
|
+
def calc(memo, last_memo, *args)
|
52
|
+
memo.merge(self => [@proc.call(*args)])
|
81
53
|
end
|
82
54
|
end
|
83
55
|
|
84
56
|
class Foldp < Node
|
85
|
-
def initialize(initial_state, proc
|
86
|
-
@
|
87
|
-
@fixed_argc, @rest_arg = fixed_argc, rest_arg
|
57
|
+
def initialize(initial_state, &proc)
|
58
|
+
@initial_state, @proc = initial_state, proc
|
88
59
|
end
|
89
60
|
|
90
|
-
def
|
91
|
-
@
|
92
|
-
if diff.has_key?(k)
|
93
|
-
[k, diff[k]]
|
94
|
-
else
|
95
|
-
[k, @state[k]]
|
96
|
-
end
|
97
|
-
}.to_h
|
61
|
+
def argc
|
62
|
+
@argc ||= @proc.parameters.select{|t, n| t == :opt}.count - 1
|
98
63
|
end
|
99
64
|
|
100
|
-
def
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
65
|
+
def update(last_state, diff)
|
66
|
+
case diff
|
67
|
+
when Hash
|
68
|
+
last_state.keys.map{|k|
|
69
|
+
if diff.has_key?(k)
|
70
|
+
[k, diff[k]]
|
71
|
+
else
|
72
|
+
[k, last_state[k]]
|
73
|
+
end
|
74
|
+
}.to_h
|
75
|
+
else
|
76
|
+
diff
|
77
|
+
end
|
108
78
|
end
|
109
79
|
|
110
|
-
def call(*
|
111
|
-
|
80
|
+
def call(memo, last_memo, *args)
|
81
|
+
last_state = last_memo.has_key?(self) ? last_memo[self].first : @initial_state
|
82
|
+
memo.merge(self => [update(last_state, @proc.call(last_state, *args))])
|
112
83
|
end
|
113
84
|
end
|
114
|
-
|
115
|
-
class
|
116
|
-
def initialize(
|
117
|
-
@
|
85
|
+
|
86
|
+
class Composite < Node
|
87
|
+
def initialize(pnode, cnode)
|
88
|
+
@pnode, @cnode = pnode, cnode
|
118
89
|
end
|
119
90
|
|
120
|
-
def
|
121
|
-
|
91
|
+
def argc
|
92
|
+
@pnode.argc
|
122
93
|
end
|
123
|
-
end
|
124
94
|
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
95
|
+
def calc(memo, last_memo, *args)
|
96
|
+
p_res = @pnode.call(memo, last_memo, *args)
|
97
|
+
n_res = @cnode.call(p_res, last_memo, *p_res[@pnode])
|
98
|
+
n_res.merge(self => n_res[@cnode])
|
99
|
+
end
|
129
100
|
end
|
130
101
|
|
131
|
-
|
132
|
-
|
133
|
-
|
102
|
+
class Bundle < Node
|
103
|
+
def initialize(*nodes)
|
104
|
+
@nodes = nodes
|
105
|
+
end
|
134
106
|
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
Lift.new(proc, fixed_argc, rest_arg)
|
139
|
-
end
|
107
|
+
def argc
|
108
|
+
@argc ||= @nodes.inject(0){|acc, n| acc + n.argc}
|
109
|
+
end
|
140
110
|
|
141
|
-
|
142
|
-
|
111
|
+
def calc(memo, last_memo, *args)
|
112
|
+
res = @nodes.inject(memo: memo, rest_args: args){|acc, n|
|
113
|
+
{
|
114
|
+
memo: n.call(acc[:memo], last_memo, *acc[:rest_args].take(n.argc)),
|
115
|
+
rest_args: acc[:rest_args].drop(n.argc)
|
116
|
+
}
|
117
|
+
}[:memo]
|
118
|
+
res.merge(self => @nodes.inject([]){|acc, n| acc + res[n]})
|
119
|
+
end
|
143
120
|
end
|
144
121
|
end
|
data/unit_test/test_tiny_frp.rb
CHANGED
@@ -5,79 +5,41 @@ module TinyFRP
|
|
5
5
|
require 'test/unit'
|
6
6
|
require $LIBRARY_ROOT_PATH + '/lib/tiny_frp.rb'
|
7
7
|
|
8
|
-
|
9
|
-
def
|
10
|
-
|
11
|
-
s2 = Signal.new(:node_b, [])
|
12
|
-
s3 = Signal.new(:node_c, [s1, s2])
|
13
|
-
s4 = Signal.new(:node_d, [s3])
|
14
|
-
s5 = Signal.new(:node_e, [s3])
|
15
|
-
s6 = Signal.new(:node_f, [s4, s5])
|
16
|
-
ps = Runtime.make_map(s6)
|
17
|
-
|
18
|
-
assert_equal([], ps[:node_a])
|
19
|
-
assert_equal([], ps[:node_b])
|
20
|
-
assert_equal([:node_a, :node_b], ps[:node_c])
|
21
|
-
assert_equal([:node_c], ps[:node_d])
|
22
|
-
assert_equal([:node_c], ps[:node_e])
|
23
|
-
assert_equal([:node_d, :node_e], ps[:node_f])
|
8
|
+
module Util
|
9
|
+
def lift(&proc)
|
10
|
+
TinyFRP::Lift.new(&proc)
|
24
11
|
end
|
25
12
|
|
26
|
-
def
|
27
|
-
|
28
|
-
s2 = Signal.new(:node_b, [])
|
29
|
-
s3 = Signal.new(:node_c, [s1, s2])
|
30
|
-
s4 = Signal.new(:node_d, [s3])
|
31
|
-
s5 = Signal.new(:node_e, [s3])
|
32
|
-
s6 = Signal.new(:node_f, [s4, s5])
|
33
|
-
cs = Runtime.traverse(s6)
|
34
|
-
|
35
|
-
assert_equal(1, cs[:node_a].size)
|
36
|
-
assert(cs[:node_a].include? [0, :node_c])
|
37
|
-
|
38
|
-
assert_equal(1, cs[:node_b].size)
|
39
|
-
assert(cs[:node_b].include? [1, :node_c])
|
40
|
-
|
41
|
-
assert_equal(2, cs[:node_c].size)
|
42
|
-
assert(cs[:node_c].include? [0, :node_d])
|
43
|
-
assert(cs[:node_c].include? [0, :node_e])
|
44
|
-
|
45
|
-
assert_equal(1, cs[:node_d].size)
|
46
|
-
assert(cs[:node_d].include? [0, :node_f])
|
47
|
-
|
48
|
-
assert_equal(1, cs[:node_e].size)
|
49
|
-
assert(cs[:node_e].include? [1, :node_f])
|
50
|
-
|
51
|
-
assert_equal(0, cs[:node_f].size)
|
13
|
+
def foldp(init_state, &proc)
|
14
|
+
TinyFRP::Foldp.new(init_state, &proc)
|
52
15
|
end
|
16
|
+
end
|
53
17
|
|
54
|
-
|
55
|
-
|
56
|
-
s1 = Signal.new(proc{ v1 = v1 + 1}, [])
|
57
|
-
s2 = Signal.new(proc{ v2 = v2 * 2}, [])
|
58
|
-
s3 = Signal.new(proc{|a, b| a + b}, [s1, s2])
|
59
|
-
|
60
|
-
assert_equal([1+2, 2+4, 3+8, 4+16, 5+32], Runtime.new(s3).run(5))
|
61
|
-
end
|
18
|
+
class TinyFRPTest < Test::Unit::TestCase
|
19
|
+
include Util
|
62
20
|
|
63
21
|
def test_lift
|
64
22
|
v1, v2 = 0, 1
|
65
|
-
|
66
|
-
|
67
|
-
signal = TinyFRP.bundle(l1, l2) >> TinyFRP.lift{|a, b| a + b}
|
68
|
-
|
69
|
-
assert_equal([1+2, 2+4, 3+8, 4+16, 5+32], Runtime.new(signal).run(5))
|
23
|
+
node = lift{|a, b| a + b} << lift{v1 = v1 + 1} + lift{v2 = v2 * 2}
|
24
|
+
assert_equal([[1+2], [2+4], [3+8], [4+16], [5+32]], TinyFRP.process(node, 5))
|
70
25
|
end
|
71
26
|
|
72
27
|
def test_foldp
|
73
|
-
|
74
|
-
|
75
|
-
|
28
|
+
node = lift{|a, b| a + b} << foldp(0){|acc| acc + 1} + foldp(1){|acc| acc * 2}
|
29
|
+
assert_equal([[1+2], [2+4], [3+8], [4+16], [5+32]], TinyFRP.process(node, 5))
|
30
|
+
end
|
76
31
|
|
77
|
-
|
32
|
+
def test_composite
|
33
|
+
node1 = foldp(0){|a| a + 1} >> lift{|a| a + 1}
|
34
|
+
node2 = foldp(0){|a| a + 1} >> lift{|a| a - 1}
|
35
|
+
node3 = lift{|a, b| a * b} << node1 + node2
|
36
|
+
assert_equal([[1 * 1 - 1], [2 * 2 - 1], [3 * 3 - 1]], TinyFRP.process(node3, 3))
|
37
|
+
end
|
38
|
+
|
39
|
+
def test_bundle
|
40
|
+
node = foldp(0){|a| a + 1} + foldp(1){|a| a + 1} + foldp(2){|a| a + 1}
|
41
|
+
assert_equal([[1, 2, 3], [2, 3, 4], [3, 4, 5]], TinyFRP.process(node, 3))
|
78
42
|
end
|
79
43
|
end
|
80
44
|
end
|
81
45
|
end
|
82
|
-
|
83
|
-
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: tiny_frp
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0
|
4
|
+
version: 1.0.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- sawaken
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2015-02-
|
11
|
+
date: 2015-02-05 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|