mercury_amqp 0.1.5 → 0.1.6
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/mercury/cps/methods.rb +18 -16
- data/lib/mercury/cps/seq.rb +15 -13
- data/lib/mercury/cps/seq_with_let.rb +51 -49
- data/lib/mercury/cps.rb +64 -62
- data/lib/mercury/utils.rb +8 -6
- data/lib/mercury/version.rb +1 -1
- data/spec/lib/mercury/cps_spec.rb +2 -0
- data/spec/lib/mercury/utils_spec.rb +2 -0
- 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: 4870a8839ae27cd315c1812fabf3657b83719894
|
4
|
+
data.tar.gz: 8f88e142bdd7353de606efb5e64952b947b8061d
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: ca6fc752c0a82c9f35d61fafa80ceed4b1cb18577c06ca8ab49377cd471ad6c8e1b14a75962e66d54bf064b65eb0786cda19bae1a8474004e4796713932916f0
|
7
|
+
data.tar.gz: 322754fee9b93640f7d32f046af978f88373484b478c5a38d71a10cdc1a48b92b58e50fd0adcbef6330b6f5163d9e6c64d7606a24c1fb21becc0a35573b4d906
|
data/lib/mercury/cps/methods.rb
CHANGED
@@ -1,23 +1,25 @@
|
|
1
|
-
class
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
1
|
+
class Mercury
|
2
|
+
class Cps
|
3
|
+
module Methods
|
4
|
+
def lift(&block)
|
5
|
+
Cps.lift(&block)
|
6
|
+
end
|
6
7
|
|
7
|
-
|
8
|
-
|
9
|
-
|
8
|
+
def seq(&block)
|
9
|
+
Cps.seq(&block)
|
10
|
+
end
|
10
11
|
|
11
|
-
|
12
|
-
|
13
|
-
|
12
|
+
def seql(&block)
|
13
|
+
Cps.seql(2, &block)
|
14
|
+
end
|
14
15
|
|
15
|
-
|
16
|
-
|
17
|
-
|
16
|
+
def seqp(&block)
|
17
|
+
Cps.seqp(&block)
|
18
|
+
end
|
18
19
|
|
19
|
-
|
20
|
-
|
20
|
+
def cps(&block)
|
21
|
+
Cps.new(&block)
|
22
|
+
end
|
21
23
|
end
|
22
24
|
end
|
23
25
|
end
|
data/lib/mercury/cps/seq.rb
CHANGED
@@ -1,19 +1,21 @@
|
|
1
|
-
class
|
1
|
+
class Mercury
|
2
|
+
class Cps
|
2
3
|
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
end
|
9
|
-
|
10
|
-
class Seq
|
11
|
-
def m
|
12
|
-
@m ||= Cps.identity # we need an initial Cps to chain onto
|
4
|
+
# Syntactic sugar for and_then chains.
|
5
|
+
def self.seq(&block)
|
6
|
+
s = Seq.new
|
7
|
+
block.call(s.method(:chain))
|
8
|
+
s.m
|
13
9
|
end
|
14
10
|
|
15
|
-
|
16
|
-
|
11
|
+
class Seq
|
12
|
+
def m
|
13
|
+
@m ||= Cps.identity # we need an initial Cps to chain onto
|
14
|
+
end
|
15
|
+
|
16
|
+
def chain(proc=nil, &block)
|
17
|
+
@m = m.and_then(&(proc || block))
|
18
|
+
end
|
17
19
|
end
|
18
20
|
end
|
19
21
|
end
|
@@ -1,67 +1,69 @@
|
|
1
1
|
require 'binding_of_caller'
|
2
2
|
|
3
|
-
class
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
3
|
+
class Mercury
|
4
|
+
class Cps
|
5
|
+
# Syntactic sugar for and_then chains.
|
6
|
+
def self.seql(depth=1, &block)
|
7
|
+
# EXPERIMENTAL
|
8
|
+
# The trick here is to execute the block in a context where
|
9
|
+
# 1. we can simulate local let-bound variables, and
|
10
|
+
# 2. the block can access variables and methods available
|
11
|
+
# outside the call to seql.
|
12
|
+
#
|
13
|
+
# To achieve this, we instance_exec the block in a SeqWithLet
|
14
|
+
# object, which provides the let bound variables (as methods)
|
15
|
+
# and uses method_missing to proxy other methods to the parent
|
16
|
+
# binding.
|
17
|
+
#
|
18
|
+
# Note: parent instance variables are not available inside the block.
|
19
|
+
# Note: keyword arguments are not proxied to methods called in the parent binding
|
20
|
+
context = SeqWithLet.new(binding.of_caller(depth))
|
21
|
+
context.instance_exec(&block)
|
22
|
+
context.__chain
|
23
|
+
end
|
23
24
|
|
24
|
-
|
25
|
+
class SeqWithLet
|
25
26
|
|
26
|
-
|
27
|
-
|
28
|
-
|
27
|
+
def and_then(&block)
|
28
|
+
@__chain = __chain.and_then(&block)
|
29
|
+
end
|
29
30
|
|
30
|
-
|
31
|
-
|
32
|
-
|
31
|
+
def and_lift(&block)
|
32
|
+
@__chain = __chain.and_lift(&block)
|
33
|
+
end
|
33
34
|
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
35
|
+
def let(name, &block)
|
36
|
+
and_then(&block)
|
37
|
+
and_then do |value|
|
38
|
+
__values[name] = value
|
39
|
+
Cps.lift{value}
|
40
|
+
end
|
39
41
|
end
|
40
|
-
end
|
41
42
|
|
42
|
-
|
43
|
-
|
44
|
-
|
43
|
+
def initialize(parent_binding)
|
44
|
+
@__parent_binding = parent_binding
|
45
|
+
end
|
45
46
|
|
46
|
-
|
47
|
-
|
48
|
-
|
47
|
+
def __chain
|
48
|
+
@__chain ||= Cps.identity
|
49
|
+
end
|
49
50
|
|
50
|
-
|
51
|
-
|
52
|
-
|
51
|
+
def method_missing(name, *args, &block)
|
52
|
+
__values.fetch(name) { __parent_call(name.to_s, *args, &block) }
|
53
|
+
end
|
53
54
|
|
54
|
-
|
55
|
-
|
55
|
+
def __parent_call(name, *args, &block)
|
56
|
+
@__parent_caller ||= @__parent_binding.eval <<-EOD
|
56
57
|
proc do |name, *args, &block|
|
57
58
|
send(name, *args, &block)
|
58
59
|
end
|
59
|
-
|
60
|
-
|
61
|
-
|
60
|
+
EOD
|
61
|
+
@__parent_caller.call(name, *args, &block)
|
62
|
+
end
|
62
63
|
|
63
|
-
|
64
|
-
|
64
|
+
def __values
|
65
|
+
@__values ||= {}
|
66
|
+
end
|
65
67
|
end
|
66
68
|
end
|
67
69
|
end
|
data/lib/mercury/cps.rb
CHANGED
@@ -13,85 +13,87 @@ require 'mercury/utils'
|
|
13
13
|
# passing. It basically wraps a CPS proc with methods for
|
14
14
|
# composing them.
|
15
15
|
# See http://codon.com/refactoring-ruby-with-monads
|
16
|
-
class
|
17
|
-
|
16
|
+
class Mercury
|
17
|
+
class Cps
|
18
|
+
attr_reader :cps
|
18
19
|
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
20
|
+
# @param [Proc] cps a CPS proc (signature: *args, &k)
|
21
|
+
def initialize(&cps)
|
22
|
+
@cps = cps
|
23
|
+
end
|
23
24
|
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
25
|
+
# Applies the wrapped proc. If the CPS return value
|
26
|
+
# is not needed, the continuation k may be omitted.
|
27
|
+
# Returns the return value of the continuation.
|
28
|
+
def run(*args, &k)
|
29
|
+
k ||= proc { |x| x }
|
30
|
+
cps.call(*args, &k)
|
31
|
+
end
|
31
32
|
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
33
|
+
# The "bind" operation; composes two Cps
|
34
|
+
# @param [Proc] pm a proc that takes the output of this
|
35
|
+
# Cps and returns a Cps
|
36
|
+
def and_then(&pm)
|
37
|
+
Cps.new do |*args, &k|
|
38
|
+
self.run(*args) do |*args2|
|
39
|
+
next_cps = pm.call(*args2)
|
40
|
+
next_cps.is_a?(Cps) or raise "'and_then' block did not return a Cps. Did you want 'and_lift'? at #{pm.source_location}"
|
41
|
+
next_cps.run(&k)
|
42
|
+
end
|
41
43
|
end
|
42
44
|
end
|
43
|
-
end
|
44
45
|
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
46
|
+
# equivalent to: and_then { lift { ... } }
|
47
|
+
def and_lift(&p)
|
48
|
+
and_then do |*args|
|
49
|
+
Cps.lift { p.call(*args) }
|
50
|
+
end
|
49
51
|
end
|
50
|
-
end
|
51
52
|
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
53
|
+
# Returns a Cps for a non-CPS proc.
|
54
|
+
def self.lift(&p)
|
55
|
+
new { |*args, &k| k.call(p.call(*args)) }
|
56
|
+
end
|
56
57
|
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
58
|
+
# The identity function as a Cps.
|
59
|
+
def self.identity
|
60
|
+
new { |*args, &k| k.call(*args) }
|
61
|
+
end
|
61
62
|
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
63
|
+
# Returns a Cps that executes the provided Cpses concurrently.
|
64
|
+
# Once all complete, their return values are passed to the continuation
|
65
|
+
# in an array with positions corresponding to the provided Cpses.
|
66
|
+
def self.concurrently(*cpss)
|
67
|
+
cpss = Utils.unsplat(cpss)
|
67
68
|
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
69
|
+
Cps.new do |*in_args, &k|
|
70
|
+
pending_completions = cpss
|
71
|
+
returned_args = []
|
72
|
+
cpss.each_with_index do |cps, i|
|
73
|
+
cps.run(*in_args) do |*out_args|
|
74
|
+
returned_args[i] = out_args
|
75
|
+
pending_completions.delete(cps)
|
76
|
+
if pending_completions.none?
|
77
|
+
k.call(returned_args)
|
78
|
+
end
|
77
79
|
end
|
78
80
|
end
|
79
81
|
end
|
80
82
|
end
|
81
|
-
end
|
82
83
|
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
84
|
+
# Calls and_then for each x.
|
85
|
+
# @yieldparam x [Object] An item from xs
|
86
|
+
# @yieldparam *args [Objects] The value(s) passed from the last action
|
87
|
+
# @yieldreturn [Cps] The next action to add to the chain
|
88
|
+
def inject(xs, &block)
|
89
|
+
xs.inject(self) do |chain, x|
|
90
|
+
chain.and_then { |*args| block.call(x, *args) }
|
91
|
+
end
|
90
92
|
end
|
91
|
-
end
|
92
93
|
|
93
|
-
|
94
|
-
|
95
|
-
|
94
|
+
# equivalent to Cps.identity.inject(...)
|
95
|
+
def self.inject(xs, &block)
|
96
|
+
Cps.identity.inject(xs, &block)
|
97
|
+
end
|
96
98
|
end
|
97
99
|
end
|
data/lib/mercury/utils.rb
CHANGED
@@ -1,9 +1,11 @@
|
|
1
|
-
class
|
2
|
-
|
3
|
-
|
4
|
-
args.first
|
5
|
-
|
6
|
-
|
1
|
+
class Mercury
|
2
|
+
class Utils
|
3
|
+
def self.unsplat(args)
|
4
|
+
if args.size == 1 and args.first.is_a?(Array)
|
5
|
+
args.first
|
6
|
+
else
|
7
|
+
args
|
8
|
+
end
|
7
9
|
end
|
8
10
|
end
|
9
11
|
end
|
data/lib/mercury/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: mercury_amqp
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1.
|
4
|
+
version: 0.1.6
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Peter Winton
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2016-02
|
11
|
+
date: 2016-03-02 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|