proc 0.0.4 → 0.3.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/README.md +80 -0
- data/lib/proc.rb +8 -0
- data/lib/proc/argument.rb +28 -0
- data/lib/proc/callable.rb +89 -6
- data/lib/proc/client.rb +48 -19
- data/lib/proc/composition.rb +68 -26
- data/lib/proc/version.rb +1 -1
- metadata +4 -5
- data/lib/proc/composition/deferable.rb +0 -29
- data/lib/proc/composition/evaluator.rb +0 -52
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: c3a73eafa61306bca405c0eaec0f8df0d145b22d27a98ee8dcf28db94cdadfa3
|
4
|
+
data.tar.gz: b1e95096528fe529ec664a370095269ae26672994178ed62e3c78159c46ed173
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 9708b1585d8c95deb6016cc5dbed10d5c7bffdfa55421d0392d3c51ec2af5ce334eb5b41283c585795874c7cdf5b035e6eb41ca145ee56d7409147546b61a6bf
|
7
|
+
data.tar.gz: ec138355afed48dde883579c73d304196b3cb2b6b8ac7d5a0986b43c5bffb6591fd33c019b516807c46b2c1ef3c6d75df7fc10d5bae10ecfbc38428ea89977c9
|
data/README.md
CHANGED
@@ -0,0 +1,80 @@
|
|
1
|
+
The `proc` gem lets you call codeless web functions through the proc.dev service.
|
2
|
+
|
3
|
+
## Getting Started
|
4
|
+
|
5
|
+
Install `proc` using the `gem` command from the command line:
|
6
|
+
|
7
|
+
```
|
8
|
+
gem install proc
|
9
|
+
```
|
10
|
+
|
11
|
+
You will also need a proc.dev account. Create a free account in seconds at [proc.dev](https://proc.dev/).
|
12
|
+
|
13
|
+
## Connecting
|
14
|
+
|
15
|
+
Sign in to your proc.dev account and locate your secret key. Use the secret to create a client connection:
|
16
|
+
|
17
|
+
```ruby
|
18
|
+
client = Proc.connect("secret-key")
|
19
|
+
```
|
20
|
+
|
21
|
+
## Calling Procs
|
22
|
+
|
23
|
+
You can call available procs through a connected client:
|
24
|
+
|
25
|
+
```ruby
|
26
|
+
client.core.string.reverse.call("hello")
|
27
|
+
=> "olleh"
|
28
|
+
```
|
29
|
+
|
30
|
+
Requests are sent to proc.dev anytime the `call` method is invoked.
|
31
|
+
|
32
|
+
## Callable Contexts
|
33
|
+
|
34
|
+
Proc lookups create contexts that can be called later:
|
35
|
+
|
36
|
+
```ruby
|
37
|
+
string = client.core.string
|
38
|
+
|
39
|
+
string.reverse.call("hello")
|
40
|
+
=> "olleh"
|
41
|
+
|
42
|
+
string.truncate.call("hello", length: 3)
|
43
|
+
=> "hel"
|
44
|
+
```
|
45
|
+
|
46
|
+
Contexts can be configured with default input and arguments using the `with` method:
|
47
|
+
|
48
|
+
```ruby
|
49
|
+
truncate = client.core.string.truncate.with("default", length: 1)
|
50
|
+
|
51
|
+
truncate.call
|
52
|
+
=> "d"
|
53
|
+
```
|
54
|
+
|
55
|
+
Default input and/or arguments can be overidden for a specific call:
|
56
|
+
|
57
|
+
```ruby
|
58
|
+
truncate.call(length: 3)
|
59
|
+
=> "def"
|
60
|
+
```
|
61
|
+
|
62
|
+
Procs can also be looked up using the hash key syntax:
|
63
|
+
|
64
|
+
```ruby
|
65
|
+
client["core.string.truncate"].call("hello", length: 3)
|
66
|
+
=> "hel"
|
67
|
+
```
|
68
|
+
|
69
|
+
## Compositions
|
70
|
+
|
71
|
+
Procs can be composed together to build more complex behavior:
|
72
|
+
|
73
|
+
```ruby
|
74
|
+
composition = client.core.string.reverse >> client.core.string.truncate(length: 3) >> client.core.string.capitalize
|
75
|
+
|
76
|
+
composition.call("hello")
|
77
|
+
=> "Oll"
|
78
|
+
```
|
79
|
+
|
80
|
+
Compositions are sent to proc.dev in a single request.
|
data/lib/proc.rb
CHANGED
@@ -0,0 +1,28 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
class Proc
|
4
|
+
class Argument
|
5
|
+
def initialize(name, **options)
|
6
|
+
@name = name
|
7
|
+
@options = options
|
8
|
+
end
|
9
|
+
|
10
|
+
def serialize
|
11
|
+
{"::" => {"name" => @name.to_s}.merge(serialized_options)}
|
12
|
+
end
|
13
|
+
|
14
|
+
def serialized_options
|
15
|
+
@options.each_pair.each_with_object({}) { |(key, value), hash|
|
16
|
+
hash[key.to_s] = serialize_value(value)
|
17
|
+
}
|
18
|
+
end
|
19
|
+
|
20
|
+
private def serialize_value(value)
|
21
|
+
if value.respond_to?(:serialize)
|
22
|
+
value.serialize
|
23
|
+
else
|
24
|
+
value
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
data/lib/proc/callable.rb
CHANGED
@@ -2,22 +2,105 @@
|
|
2
2
|
|
3
3
|
class Proc
|
4
4
|
class Callable
|
5
|
-
attr_reader :proc
|
5
|
+
attr_reader :proc, :input, :arguments
|
6
6
|
|
7
|
-
def initialize(proc, client:)
|
8
|
-
@proc = proc
|
7
|
+
def initialize(proc, client:, input: Proc.undefined, arguments: {})
|
8
|
+
@proc = proc.to_s
|
9
9
|
@client = client
|
10
|
+
@input = input
|
11
|
+
@arguments = arguments
|
10
12
|
end
|
11
13
|
|
12
|
-
def
|
13
|
-
@
|
14
|
+
def initialize_copy(_)
|
15
|
+
@input = input.dup
|
16
|
+
@arguments = arguments.dup
|
17
|
+
end
|
18
|
+
|
19
|
+
def call(input = input_omitted = true, **arguments)
|
20
|
+
callable = self.class.new(
|
21
|
+
@proc,
|
22
|
+
client: @client,
|
23
|
+
input: input_omitted ? @input : input,
|
24
|
+
arguments: @arguments.merge(arguments)
|
25
|
+
)
|
26
|
+
|
27
|
+
@client.call(@proc, callable.serialized_input, **callable.serialized_arguments)
|
28
|
+
end
|
29
|
+
|
30
|
+
def with(input = input_omitted = true, **arguments)
|
31
|
+
self.class.new(
|
32
|
+
@proc,
|
33
|
+
client: @client,
|
34
|
+
input: input_omitted ? @input : input,
|
35
|
+
arguments: @arguments.merge(arguments)
|
36
|
+
)
|
14
37
|
end
|
15
38
|
|
16
39
|
def >>(other)
|
17
|
-
composed = Composition.new(client: @client)
|
40
|
+
composed = Composition.new(client: @client, input: @input)
|
18
41
|
composed << self
|
19
42
|
composed << other
|
20
43
|
composed
|
21
44
|
end
|
45
|
+
|
46
|
+
def serialize
|
47
|
+
wrapped = {"[]" => [[@proc, serialized_arguments]]}
|
48
|
+
|
49
|
+
unless Proc.undefined?(@input)
|
50
|
+
wrapped["<<"] = serialized_input
|
51
|
+
end
|
52
|
+
|
53
|
+
{"{}" => wrapped}
|
54
|
+
end
|
55
|
+
|
56
|
+
def serialized_input
|
57
|
+
serialize_value(@input)
|
58
|
+
end
|
59
|
+
|
60
|
+
def serialized_arguments
|
61
|
+
@arguments.each_pair.each_with_object({}) { |(key, value), hash|
|
62
|
+
hash[key.to_s] = serialize_value(value)
|
63
|
+
}
|
64
|
+
end
|
65
|
+
|
66
|
+
def [](proc)
|
67
|
+
Callable.new(
|
68
|
+
[@proc, proc].join("."),
|
69
|
+
client: @client,
|
70
|
+
input: @input,
|
71
|
+
arguments: @arguments
|
72
|
+
)
|
73
|
+
end
|
74
|
+
|
75
|
+
IGNORE_MISSING = %i[to_hash].freeze
|
76
|
+
|
77
|
+
def method_missing(name, input = input_omitted = true, **arguments)
|
78
|
+
if IGNORE_MISSING.include?(name)
|
79
|
+
super
|
80
|
+
else
|
81
|
+
Callable.new(
|
82
|
+
[@proc, name].join("."),
|
83
|
+
client: @client,
|
84
|
+
input: input_omitted ? @input : input,
|
85
|
+
arguments: @arguments.merge(arguments)
|
86
|
+
)
|
87
|
+
end
|
88
|
+
end
|
89
|
+
|
90
|
+
def respond_to_missing?(name, *)
|
91
|
+
if IGNORE_MISSING.include?(name)
|
92
|
+
super
|
93
|
+
else
|
94
|
+
true
|
95
|
+
end
|
96
|
+
end
|
97
|
+
|
98
|
+
private def serialize_value(value)
|
99
|
+
if value.respond_to?(:serialize)
|
100
|
+
value.serialize
|
101
|
+
else
|
102
|
+
value
|
103
|
+
end
|
104
|
+
end
|
22
105
|
end
|
23
106
|
end
|
data/lib/proc/client.rb
CHANGED
@@ -3,6 +3,7 @@
|
|
3
3
|
require "async"
|
4
4
|
require "oj"
|
5
5
|
|
6
|
+
require_relative "argument"
|
6
7
|
require_relative "callable"
|
7
8
|
require_relative "composition"
|
8
9
|
require_relative "null_logger"
|
@@ -13,7 +14,7 @@ class Proc
|
|
13
14
|
class Error < StandardError
|
14
15
|
end
|
15
16
|
|
16
|
-
class
|
17
|
+
class Invalid < ::ArgumentError
|
17
18
|
end
|
18
19
|
|
19
20
|
class Undefined < ::NameError
|
@@ -22,10 +23,13 @@ class Proc
|
|
22
23
|
class Unauthorized < Error
|
23
24
|
end
|
24
25
|
|
26
|
+
class Forbidden < Error
|
27
|
+
end
|
28
|
+
|
25
29
|
class Unavailable < Error
|
26
30
|
end
|
27
31
|
|
28
|
-
class
|
32
|
+
class Limited < Error
|
29
33
|
end
|
30
34
|
|
31
35
|
class Timeout < Error
|
@@ -60,10 +64,6 @@ class Proc
|
|
60
64
|
@resets_at
|
61
65
|
end
|
62
66
|
|
63
|
-
def compose(&block)
|
64
|
-
Composition.new(client: self, &block)
|
65
|
-
end
|
66
|
-
|
67
67
|
DEFAULT_HEADERS = {
|
68
68
|
"accept" => "application/json",
|
69
69
|
"content-type" => "application/json"
|
@@ -71,14 +71,14 @@ class Proc
|
|
71
71
|
|
72
72
|
def call(proc = nil, input = nil, **arguments)
|
73
73
|
Async(logger: NullLogger) { |task|
|
74
|
-
body = {
|
74
|
+
body = {"<>" => true}
|
75
|
+
|
76
|
+
unless Proc.undefined?(input)
|
77
|
+
body["<<"] = serialize_value(input)
|
78
|
+
end
|
75
79
|
|
76
80
|
arguments.each_pair do |key, value|
|
77
|
-
body[key.to_s] =
|
78
|
-
value.serialize
|
79
|
-
else
|
80
|
-
value
|
81
|
-
end
|
81
|
+
body[key.to_s] = serialize_value(value)
|
82
82
|
end
|
83
83
|
|
84
84
|
headers = {
|
@@ -86,14 +86,14 @@ class Proc
|
|
86
86
|
}.merge(DEFAULT_HEADERS)
|
87
87
|
|
88
88
|
begin
|
89
|
-
response = super(:post, build_uri(proc), headers: headers, body: Oj.dump(body, mode: :
|
89
|
+
response = super(:post, build_uri(proc), headers: headers, body: Oj.dump(body, mode: :custom), task: task)
|
90
90
|
|
91
91
|
@remaining = response.headers["x-rate-limit-remaining"].to_s.to_i
|
92
92
|
@resets_at = Time.at(response.headers["x-rate-limit-reset"].to_s.to_i)
|
93
93
|
|
94
|
-
payload = Oj.load(response.read, mode: :
|
95
|
-
rescue
|
96
|
-
raise Proc::Unavailable
|
94
|
+
payload = Oj.load(response.read, mode: :compat)
|
95
|
+
rescue
|
96
|
+
raise Proc::Unavailable
|
97
97
|
ensure
|
98
98
|
response&.close
|
99
99
|
end
|
@@ -102,27 +102,56 @@ class Proc
|
|
102
102
|
when 200
|
103
103
|
payload[">>"]
|
104
104
|
when 400
|
105
|
-
raise Proc::
|
106
|
-
when
|
105
|
+
raise Proc::Invalid, payload.dig("error", "message")
|
106
|
+
when 401
|
107
107
|
raise Proc::Unauthorized, payload.dig("error", "message")
|
108
|
+
when 403
|
109
|
+
raise Proc::Forbidden, payload.dig("error", "message")
|
108
110
|
when 404
|
109
111
|
raise Proc::Undefined, payload.dig("error", "message")
|
110
112
|
when 408
|
111
113
|
raise Proc::Timeout, payload.dig("error", "message")
|
112
114
|
when 429
|
113
|
-
raise Proc::
|
115
|
+
raise Proc::Limited, payload.dig("error", "message")
|
114
116
|
when 500
|
115
117
|
raise Proc::Error, payload.dig("error", "message")
|
118
|
+
when 508
|
119
|
+
raise Proc::Error, payload.dig("error", "message")
|
116
120
|
else
|
117
121
|
raise Proc::Error, "unhandled"
|
118
122
|
end
|
119
123
|
}.wait
|
120
124
|
end
|
121
125
|
|
126
|
+
def method_missing(name, input = input_omitted = true, **arguments)
|
127
|
+
if input_omitted
|
128
|
+
Callable.new(name, client: self, arguments: arguments)
|
129
|
+
else
|
130
|
+
Callable.new(name, client: self, input: input, arguments: arguments)
|
131
|
+
end
|
132
|
+
end
|
133
|
+
|
134
|
+
def respond_to_missing?(name, *)
|
135
|
+
true
|
136
|
+
end
|
137
|
+
|
138
|
+
def argument(name, **options)
|
139
|
+
Argument.new(name, **options)
|
140
|
+
end
|
141
|
+
alias_method :arg, :argument
|
142
|
+
|
122
143
|
private def build_uri(proc)
|
123
144
|
host_and_path = File.join(@host, proc.to_s.split(".").join("/"))
|
124
145
|
|
125
146
|
"#{@scheme}://#{host_and_path}"
|
126
147
|
end
|
148
|
+
|
149
|
+
private def serialize_value(value)
|
150
|
+
if value.respond_to?(:serialize)
|
151
|
+
value.serialize
|
152
|
+
else
|
153
|
+
value
|
154
|
+
end
|
155
|
+
end
|
127
156
|
end
|
128
157
|
end
|
data/lib/proc/composition.rb
CHANGED
@@ -2,23 +2,37 @@
|
|
2
2
|
|
3
3
|
class Proc
|
4
4
|
class Composition
|
5
|
-
|
6
|
-
require_relative "composition/evaluator"
|
5
|
+
attr_reader :input, :callables, :arguments
|
7
6
|
|
8
|
-
def initialize(client:,
|
7
|
+
def initialize(client:, input:, callables: [], arguments: {})
|
9
8
|
@client = client
|
10
|
-
@
|
11
|
-
@callables =
|
9
|
+
@input = input
|
10
|
+
@callables = callables
|
11
|
+
@arguments = arguments
|
12
12
|
end
|
13
13
|
|
14
14
|
def initialize_copy(_)
|
15
15
|
@callables = @callables.dup
|
16
16
|
end
|
17
17
|
|
18
|
-
def call(input =
|
19
|
-
|
20
|
-
|
21
|
-
|
18
|
+
def call(input = input_omitted = true, **arguments)
|
19
|
+
callable = self.class.new(
|
20
|
+
client: @client,
|
21
|
+
input: input_omitted ? @input : input,
|
22
|
+
callables: @callables.dup,
|
23
|
+
arguments: @arguments.merge(arguments)
|
24
|
+
)
|
25
|
+
|
26
|
+
@client.call("proc.exec", nil, proc: callable.serialize)
|
27
|
+
end
|
28
|
+
|
29
|
+
def with(input = input_omitted = true, **arguments)
|
30
|
+
self.class.new(
|
31
|
+
client: @client,
|
32
|
+
input: input_omitted ? @input : input,
|
33
|
+
callables: @callables.dup,
|
34
|
+
arguments: @arguments.merge(arguments)
|
35
|
+
)
|
22
36
|
end
|
23
37
|
|
24
38
|
def >>(other)
|
@@ -28,31 +42,59 @@ class Proc
|
|
28
42
|
end
|
29
43
|
|
30
44
|
def <<(callable)
|
31
|
-
|
45
|
+
case callable
|
46
|
+
when Composition
|
47
|
+
merge(callable)
|
48
|
+
when Callable
|
49
|
+
@callables << callable
|
50
|
+
end
|
32
51
|
end
|
33
52
|
|
34
|
-
def
|
35
|
-
|
53
|
+
def serialize
|
54
|
+
wrapped = {"[]" => serialized_calls}
|
55
|
+
|
56
|
+
unless Proc.undefined?(@input)
|
57
|
+
wrapped["<<"] = serialized_input
|
58
|
+
end
|
59
|
+
|
60
|
+
{"{}" => wrapped.merge(serialized_arguments)}
|
36
61
|
end
|
37
62
|
|
38
|
-
def
|
39
|
-
|
40
|
-
|
41
|
-
|
63
|
+
def serialized_calls
|
64
|
+
@callables.map { |callable|
|
65
|
+
arguments = callable.serialized_arguments
|
66
|
+
|
67
|
+
unless Proc.undefined?(callable.input)
|
68
|
+
arguments["<<"] = callable.serialized_input
|
69
|
+
end
|
70
|
+
|
71
|
+
[callable.proc, arguments]
|
72
|
+
}
|
42
73
|
end
|
43
74
|
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
else
|
48
|
-
Evaluator.new
|
49
|
-
end
|
75
|
+
def serialized_input
|
76
|
+
serialize_value(@input)
|
77
|
+
end
|
50
78
|
|
51
|
-
|
52
|
-
|
53
|
-
|
79
|
+
def serialized_arguments
|
80
|
+
@arguments.each_pair.each_with_object({}) { |(key, value), hash|
|
81
|
+
hash[key.to_s] = serialize_value(value)
|
82
|
+
}
|
83
|
+
end
|
54
84
|
|
55
|
-
|
85
|
+
def merge(composition)
|
86
|
+
raise ArgumentError, "expected a composition" unless composition.is_a?(self.class)
|
87
|
+
|
88
|
+
@callables.concat(composition.callables)
|
89
|
+
@arguments.merge!(composition.arguments)
|
90
|
+
end
|
91
|
+
|
92
|
+
private def serialize_value(value)
|
93
|
+
if value.respond_to?(:serialize)
|
94
|
+
value.serialize
|
95
|
+
else
|
96
|
+
value
|
97
|
+
end
|
56
98
|
end
|
57
99
|
end
|
58
100
|
end
|
data/lib/proc/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: proc
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0
|
4
|
+
version: 0.3.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Bryan Powell
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2020-
|
11
|
+
date: 2020-11-23 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: async-http
|
@@ -47,11 +47,10 @@ files:
|
|
47
47
|
- LICENSE
|
48
48
|
- README.md
|
49
49
|
- lib/proc.rb
|
50
|
+
- lib/proc/argument.rb
|
50
51
|
- lib/proc/callable.rb
|
51
52
|
- lib/proc/client.rb
|
52
53
|
- lib/proc/composition.rb
|
53
|
-
- lib/proc/composition/deferable.rb
|
54
|
-
- lib/proc/composition/evaluator.rb
|
55
54
|
- lib/proc/http/client.rb
|
56
55
|
- lib/proc/http/request.rb
|
57
56
|
- lib/proc/http/response.rb
|
@@ -76,7 +75,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
76
75
|
- !ruby/object:Gem::Version
|
77
76
|
version: '0'
|
78
77
|
requirements: []
|
79
|
-
rubygems_version: 3.1.
|
78
|
+
rubygems_version: 3.1.4
|
80
79
|
signing_key:
|
81
80
|
specification_version: 4
|
82
81
|
summary: Proc client library.
|
@@ -1,29 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
class Proc
|
4
|
-
class Composition
|
5
|
-
class Deferable
|
6
|
-
attr_reader :proc
|
7
|
-
attr_writer :arguments
|
8
|
-
|
9
|
-
def initialize(proc)
|
10
|
-
@proc = proc
|
11
|
-
@arguments = {}
|
12
|
-
end
|
13
|
-
|
14
|
-
def serialize
|
15
|
-
[@proc, serialized_arguments]
|
16
|
-
end
|
17
|
-
|
18
|
-
private def serialized_arguments
|
19
|
-
@arguments.each.each_with_object({}) do |(key, value), hash|
|
20
|
-
hash[key] = if value.respond_to?(:serialize)
|
21
|
-
value.serialize
|
22
|
-
else
|
23
|
-
value
|
24
|
-
end
|
25
|
-
end
|
26
|
-
end
|
27
|
-
end
|
28
|
-
end
|
29
|
-
end
|
@@ -1,52 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
class Proc
|
4
|
-
class Composition
|
5
|
-
class Evaluator
|
6
|
-
attr_reader :callables
|
7
|
-
|
8
|
-
def initialize
|
9
|
-
@callables = []
|
10
|
-
end
|
11
|
-
|
12
|
-
def initialize_copy(_)
|
13
|
-
@callables = @callables.map(&:dup)
|
14
|
-
end
|
15
|
-
|
16
|
-
def [](proc)
|
17
|
-
evaluator = dup
|
18
|
-
evaluator << Deferable.new(proc)
|
19
|
-
evaluator
|
20
|
-
end
|
21
|
-
|
22
|
-
def <<(proc)
|
23
|
-
@callables << proc
|
24
|
-
end
|
25
|
-
|
26
|
-
def >>(other)
|
27
|
-
evaluator = dup
|
28
|
-
|
29
|
-
case other
|
30
|
-
when Evaluator
|
31
|
-
other.callables.each do |each_callable|
|
32
|
-
evaluator << each_callable
|
33
|
-
end
|
34
|
-
when Callable
|
35
|
-
evaluator << Deferable.new(other.proc)
|
36
|
-
end
|
37
|
-
|
38
|
-
evaluator
|
39
|
-
end
|
40
|
-
|
41
|
-
def call(**arguments)
|
42
|
-
evaluator = dup
|
43
|
-
evaluator.callables.last.arguments = arguments
|
44
|
-
evaluator
|
45
|
-
end
|
46
|
-
|
47
|
-
def serialize
|
48
|
-
{ "[]" => @callables.map(&:serialize) }
|
49
|
-
end
|
50
|
-
end
|
51
|
-
end
|
52
|
-
end
|