fdk 0.0.14 → 0.0.15
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +5 -5
- data/README.md +2 -0
- data/Rakefile +6 -0
- data/lib/fdk/call.rb +61 -0
- data/lib/fdk/context.rb +40 -62
- data/lib/fdk/function.rb +22 -0
- data/lib/fdk/listener.rb +68 -0
- data/lib/fdk/runner.rb +3 -131
- data/lib/fdk/support_classes.rb +21 -0
- data/lib/fdk/version.rb +1 -1
- data/lib/fdk.rb +7 -3
- metadata +7 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
|
-
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 54156518eff40553f0490bcf437fa82daf307ce4
|
4
|
+
data.tar.gz: 73e6aed064fa66529f22777f8788e9292828ff90
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: b47e349ed1fcc96d5ab2170ad2bafeddeba810246c4457149fd160cb164e4f1dae32b8172ddff9307a11707010a3657770417e6176fe058ba267ebe21431d1bb
|
7
|
+
data.tar.gz: dc5ba5aaadb49d99ee180098700970f36b8bb258086c723c058d4a8f0718077cf6dfc9898e704fd974c4aec649ef94a310ba8fcfb32591f3bd3ef41f902e199e
|
data/README.md
CHANGED
@@ -1,6 +1,8 @@
|
|
1
1
|
# Ruby Function Developer Kit (FDK)
|
2
2
|
This provides a Ruby framework for developing functions for use with [Fn](https://fnproject.github.io).
|
3
3
|
|
4
|
+
[![CircleCI](https://circleci.com/gh/fnproject/fdk-ruby.svg?style=svg)](https://circleci.com/gh/fnproject/fdk-ruby)
|
5
|
+
|
4
6
|
## Function Handler
|
5
7
|
To use this FDK, you simply need to require this gem.
|
6
8
|
|
data/Rakefile
CHANGED
data/lib/fdk/call.rb
ADDED
@@ -0,0 +1,61 @@
|
|
1
|
+
module FDK
|
2
|
+
# Call represents a call to the target function or lambda
|
3
|
+
class Call
|
4
|
+
FILTER_HEADERS = ["content-length", "te", "transfer-encoding",
|
5
|
+
"upgrade", "trailer"].freeze
|
6
|
+
|
7
|
+
attr_reader :request, :response
|
8
|
+
attr_accessor :error
|
9
|
+
|
10
|
+
def initialize(request:, response:)
|
11
|
+
@request = request
|
12
|
+
@response = response
|
13
|
+
end
|
14
|
+
|
15
|
+
def context
|
16
|
+
@context ||= FDK::Context.new(headers_in, headers_out)
|
17
|
+
end
|
18
|
+
|
19
|
+
def input
|
20
|
+
@input ||= ParsedInput.new(raw_input: request.body.to_s)
|
21
|
+
end
|
22
|
+
|
23
|
+
def headers_out
|
24
|
+
@headers_out ||= FDK::OutHeaders.new({}, nil)
|
25
|
+
end
|
26
|
+
|
27
|
+
def headers_in
|
28
|
+
@headers_in ||= FDK::InHeaders.new(filtered_request_header, nil)
|
29
|
+
end
|
30
|
+
|
31
|
+
def filtered_request_header
|
32
|
+
request.header.reject { |k| FILTER_HEADERS.include? k }
|
33
|
+
end
|
34
|
+
|
35
|
+
def process
|
36
|
+
format_response_body(fn_return: yield(context: context, input: input.parsed))
|
37
|
+
good_response
|
38
|
+
rescue StandardError => e
|
39
|
+
error_response(error: e)
|
40
|
+
end
|
41
|
+
|
42
|
+
def format_response_body(fn_return:)
|
43
|
+
return response.body = fn_return.to_s unless fn_return.respond_to?(:to_json)
|
44
|
+
|
45
|
+
response.body = fn_return.to_json
|
46
|
+
response["content-type"] = "application/json" unless response["content-type"]
|
47
|
+
end
|
48
|
+
|
49
|
+
def good_response
|
50
|
+
response.status = 200
|
51
|
+
headers_out.each { |k, v| response[k] = v.join(",") }
|
52
|
+
end
|
53
|
+
|
54
|
+
def error_response(error:)
|
55
|
+
response["content-type"] = "application/json"
|
56
|
+
response.status = 502
|
57
|
+
response.body = { message: "An error occurred in the function",
|
58
|
+
detail: error.to_s }.to_json
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
data/lib/fdk/context.rb
CHANGED
@@ -1,7 +1,6 @@
|
|
1
|
-
require
|
1
|
+
require "date"
|
2
2
|
|
3
3
|
module FDK
|
4
|
-
|
5
4
|
# Config looks up values in the env vars
|
6
5
|
class Config
|
7
6
|
def [](key)
|
@@ -9,67 +8,59 @@ module FDK
|
|
9
8
|
end
|
10
9
|
end
|
11
10
|
|
12
|
-
|
11
|
+
# Represents inbound HTTP headers
|
13
12
|
class InHeaders
|
14
|
-
def initialize
|
15
|
-
@headers =
|
13
|
+
def initialize(headers, key_fn)
|
14
|
+
@headers = headers
|
16
15
|
@key_fn = key_fn
|
17
|
-
|
18
16
|
end
|
19
17
|
|
20
|
-
def
|
21
|
-
if @key_fn
|
22
|
-
key = @key_fn.call(key)
|
23
|
-
end
|
18
|
+
def header_key(key)
|
19
|
+
key = @key_fn.call(key) if @key_fn
|
24
20
|
key.downcase
|
25
21
|
end
|
26
22
|
|
27
23
|
def [](key)
|
28
|
-
h = @headers[
|
29
|
-
unless h.nil?
|
30
|
-
return h[0]
|
31
|
-
end
|
32
|
-
nil
|
24
|
+
h = @headers[header_key(key)]
|
25
|
+
return h[0] unless h.nil?
|
33
26
|
end
|
34
27
|
|
35
|
-
def each
|
36
|
-
@headers.each
|
28
|
+
def each(&block)
|
29
|
+
@headers.each(&block)
|
37
30
|
end
|
38
31
|
end
|
39
32
|
|
33
|
+
# Represents outbound HTTP headers
|
40
34
|
class OutHeaders < InHeaders
|
41
|
-
|
42
|
-
|
43
|
-
super(h, key_in_fn)
|
35
|
+
def initialize(headers, key_in_fn)
|
36
|
+
super(headers, key_in_fn)
|
44
37
|
end
|
45
38
|
|
46
|
-
|
47
39
|
def []=(key, value)
|
48
40
|
if value.is_a? Array
|
49
41
|
h = []
|
50
|
-
value.each {|x| h.push(x.to_s)}
|
51
|
-
@headers[
|
42
|
+
value.each { |x| h.push(x.to_s) }
|
43
|
+
@headers[header_key(key)] = h
|
52
44
|
else
|
53
|
-
@headers[
|
45
|
+
@headers[header_key(key)] = [value.to_s]
|
54
46
|
end
|
55
47
|
end
|
56
48
|
|
57
49
|
def delete(key)
|
58
|
-
@headers.delete
|
50
|
+
@headers.delete header_key(key)
|
59
51
|
end
|
60
52
|
end
|
61
53
|
|
62
|
-
|
54
|
+
# Represents the Fn context for a function execution
|
63
55
|
class Context
|
64
|
-
|
56
|
+
# FN_APP_ID -the ID of the application that this function is a member of.
|
57
|
+
# FN_APP_NAME - the name of the application.
|
65
58
|
# FN_CALL_ID - a unique ID for each function execution.
|
66
|
-
#
|
67
|
-
# FN_HEADER_$X - the HTTP headers that were set for this request. Replace $X with the upper cased name of the header and replace dashes in the header with underscores.
|
68
|
-
# $X - any configuration values you've set for the Application or the Route. Replace X with the upper cased name of the config variable you set. Ex: minio_secret=secret will be exposed via MINIO_SECRET env var.
|
69
|
-
# FN_APP_NAME - the name of the application that matched this route, eg: myapp
|
70
|
-
# FN_METHOD - the HTTP method for the request, eg: GET or POST
|
59
|
+
# FN_FN_ID - the ID of this function
|
71
60
|
# FN_MEMORY - a number representing the amount of memory available to the call, in MB
|
72
|
-
|
61
|
+
# $X - any configuration values you've set for the Application.
|
62
|
+
# Replace X with the upper cased name of the config variable you set.
|
63
|
+
# e.g. minio_secret=secret will be exposed via MINIO_SECRET env var.
|
73
64
|
|
74
65
|
attr_reader :headers
|
75
66
|
attr_reader :response_headers
|
@@ -80,31 +71,28 @@ module FDK
|
|
80
71
|
@config ||= Config.new
|
81
72
|
end
|
82
73
|
|
83
|
-
|
84
74
|
def call_id
|
85
|
-
@headers[
|
75
|
+
@headers["fn-call-id"]
|
86
76
|
end
|
87
77
|
|
88
|
-
|
89
78
|
def app_id
|
90
|
-
@config[
|
79
|
+
@config["FN_APP_ID"]
|
91
80
|
end
|
92
81
|
|
93
|
-
|
94
82
|
def fn_id
|
95
|
-
@config[
|
83
|
+
@config["FN_FN_ID"]
|
96
84
|
end
|
97
85
|
|
98
86
|
def deadline
|
99
|
-
DateTime.iso8601(@headers[
|
87
|
+
DateTime.iso8601(@headers["fn-deadline"])
|
100
88
|
end
|
101
89
|
|
102
90
|
def memory
|
103
|
-
@config[
|
91
|
+
@config["FN_MEMORY"].to_i
|
104
92
|
end
|
105
93
|
|
106
94
|
def content_type
|
107
|
-
@headers[
|
95
|
+
@headers["content-type"]
|
108
96
|
end
|
109
97
|
|
110
98
|
def http_context
|
@@ -112,43 +100,33 @@ module FDK
|
|
112
100
|
end
|
113
101
|
end
|
114
102
|
|
115
|
-
|
103
|
+
# Represents the context data (inbound && outbound)
|
104
|
+
# for the execution passed as HTTP headers
|
116
105
|
class HTTPContext
|
117
|
-
|
118
106
|
attr_reader :headers
|
119
107
|
attr_reader :response_headers
|
120
108
|
|
121
109
|
def initialize(ctx)
|
122
|
-
|
110
|
+
fn_http_h_ = "fn-http-h-"
|
123
111
|
@ctx = ctx
|
124
|
-
|
125
|
-
|
126
112
|
http_headers = {}
|
127
|
-
ctx.headers.each
|
128
|
-
if k.downcase.start_with?(
|
129
|
-
|
130
|
-
http_headers[new_key] = v
|
131
|
-
end
|
132
|
-
}
|
133
|
-
|
113
|
+
ctx.headers.each do |k, v|
|
114
|
+
http_headers[k.sub(fn_http_h_, "")] = v if k.downcase.start_with?(fn_http_h_)
|
115
|
+
end
|
134
116
|
@headers = InHeaders.new(http_headers, nil)
|
135
|
-
@response_headers = OutHeaders.new(ctx.response_headers,
|
117
|
+
@response_headers = OutHeaders.new(ctx.response_headers, ->(s) { fn_http_h_ + s })
|
136
118
|
end
|
137
119
|
|
138
|
-
|
139
120
|
def request_url
|
140
|
-
@ctx.headers[
|
121
|
+
@ctx.headers["fn-http-request-url"]
|
141
122
|
end
|
142
123
|
|
143
124
|
def method
|
144
|
-
@ctx.headers[
|
125
|
+
@ctx.headers["fn-http-method"]
|
145
126
|
end
|
146
127
|
|
147
|
-
|
148
128
|
def status_code=(val)
|
149
|
-
@ctx.response_headers[
|
129
|
+
@ctx.response_headers["fn-http-status"] = val.to_i
|
150
130
|
end
|
151
|
-
|
152
131
|
end
|
153
132
|
end
|
154
|
-
|
data/lib/fdk/function.rb
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
module FDK
|
2
|
+
# Function represents a function function or lambda
|
3
|
+
class Function
|
4
|
+
attr_reader :format, :function
|
5
|
+
def initialize(function:, format:)
|
6
|
+
raise "'#{format}' not supported in Ruby FDK." unless format == "http-stream"
|
7
|
+
|
8
|
+
@format = format
|
9
|
+
@function = function
|
10
|
+
end
|
11
|
+
|
12
|
+
def as_proc
|
13
|
+
return function if function.respond_to?(:call)
|
14
|
+
|
15
|
+
->(context:, input:) { send(function, context: context, input: input) }
|
16
|
+
end
|
17
|
+
|
18
|
+
def call(request:, response:)
|
19
|
+
Call.new(request: request, response: response).process(&as_proc)
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
data/lib/fdk/listener.rb
ADDED
@@ -0,0 +1,68 @@
|
|
1
|
+
module FDK
|
2
|
+
# Represents the socket that Fn uses to communicate
|
3
|
+
# with the FDK (and thence the function)
|
4
|
+
# To avoid Fn trying to connect to the socket before
|
5
|
+
# it's ready, the Listener creates a socket on (private_socket_path).
|
6
|
+
#
|
7
|
+
# When the socket is ready to accept connections,
|
8
|
+
# the FDK links the private_socket_path to the socket_path.
|
9
|
+
#
|
10
|
+
# Fn waits for the socket_path to be created and then connects
|
11
|
+
class Listener
|
12
|
+
attr_reader :url, :private_socket
|
13
|
+
|
14
|
+
def initialize(url:)
|
15
|
+
if url.nil? || !url.start_with?("unix:/")
|
16
|
+
raise "Missing or invalid socket URL in FN_LISTENER."
|
17
|
+
end
|
18
|
+
|
19
|
+
@url = url
|
20
|
+
@private_socket = UNIXServer.open(private_socket_path)
|
21
|
+
end
|
22
|
+
|
23
|
+
def socket
|
24
|
+
link_socket_file unless @socket
|
25
|
+
@socket ||= private_socket
|
26
|
+
end
|
27
|
+
|
28
|
+
def link_socket_file
|
29
|
+
File.chmod(0o666, private_socket_path)
|
30
|
+
FileUtils.ln_s(File.basename(private_socket_path), socket_path)
|
31
|
+
FDK.debug "listening on #{private_socket_path}->#{socket_path}"
|
32
|
+
end
|
33
|
+
|
34
|
+
def listen(&block)
|
35
|
+
local_socket = socket.accept
|
36
|
+
begin
|
37
|
+
raise StandardError("No block given") unless block_given?
|
38
|
+
|
39
|
+
handle_requests(socket: local_socket, fn_block: block)
|
40
|
+
rescue StandardError => e
|
41
|
+
STDERR.puts "Error in request handling #{e}"
|
42
|
+
STDERR.puts e.backtrace
|
43
|
+
end
|
44
|
+
local_socket.close
|
45
|
+
end
|
46
|
+
|
47
|
+
def handle_requests(socket:, fn_block:)
|
48
|
+
loop do
|
49
|
+
req = WEBrick::HTTPRequest.new(WEBrick::Config::HTTP)
|
50
|
+
resp = WEBrick::HTTPResponse.new(WEBrick::Config::HTTP)
|
51
|
+
req.parse(socket)
|
52
|
+
FDK.debug "got request #{req}"
|
53
|
+
fn_block.call(req, resp)
|
54
|
+
resp.send_response(socket)
|
55
|
+
FDK.debug "sending resp #{resp.status}, #{resp.header}"
|
56
|
+
break unless req.keep_alive?
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
def socket_path
|
61
|
+
@socket_path ||= url[5..url.length]
|
62
|
+
end
|
63
|
+
|
64
|
+
def private_socket_path
|
65
|
+
socket_path + ".private"
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
data/lib/fdk/runner.rb
CHANGED
@@ -7,144 +7,16 @@ require "set"
|
|
7
7
|
# Executes it with input
|
8
8
|
# Responds with output
|
9
9
|
module FDK
|
10
|
-
@filter_headers = Set["content-length", "te", "transfer-encoding",
|
11
|
-
"upgrade", "trailer"]
|
12
|
-
|
13
|
-
def self.check_format
|
14
|
-
f = ENV["FN_FORMAT"]
|
15
|
-
raise "'#{f}' not supported in Ruby FDK." unless f == "http-stream"
|
16
|
-
|
17
|
-
f
|
18
|
-
end
|
19
|
-
private_class_method :check_format
|
20
|
-
|
21
|
-
def self.listener
|
22
|
-
l = ENV["FN_LISTENER"]
|
23
|
-
if l.nil? || !l.start_with?("unix:/")
|
24
|
-
raise "Missing or invalid socket URL in FN_LISTENER."
|
25
|
-
end
|
26
|
-
|
27
|
-
l
|
28
|
-
end
|
29
|
-
private_class_method :listener
|
30
|
-
|
31
10
|
@dbg = ENV["FDK_DEBUG"]
|
32
11
|
|
33
12
|
def self.debug(msg)
|
34
13
|
STDERR.puts(msg) if @dbg
|
35
14
|
end
|
36
|
-
private_class_method :debug
|
37
15
|
|
38
16
|
def self.handle(target:)
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
# When the socket is ready to accept connections,
|
43
|
-
# the FDK links the tmp_file to the socket_file.
|
44
|
-
#
|
45
|
-
# Fn waits for the socket_file to be created and then connects
|
46
|
-
check_format
|
47
|
-
l = listener
|
48
|
-
socket_file = l[5..l.length]
|
49
|
-
tmp_file = socket_file + ".tmp"
|
50
|
-
|
51
|
-
debug tmp_file
|
52
|
-
debug socket_file
|
53
|
-
UNIXServer.open(tmp_file) do |serv|
|
54
|
-
File.chmod(0o666, tmp_file)
|
55
|
-
debug "listening on #{tmp_file}->#{socket_file}"
|
56
|
-
FileUtils.ln_s(File.basename(tmp_file), socket_file)
|
57
|
-
|
58
|
-
loop do
|
59
|
-
s = serv.accept
|
60
|
-
begin
|
61
|
-
loop do
|
62
|
-
req = WEBrick::HTTPRequest.new(WEBrick::Config::HTTP)
|
63
|
-
req.parse s
|
64
|
-
debug "got request #{req}"
|
65
|
-
resp = WEBrick::HTTPResponse.new(WEBrick::Config::HTTP)
|
66
|
-
resp.status = 200
|
67
|
-
handle_call(target, req, resp)
|
68
|
-
resp.send_response s
|
69
|
-
debug "sending resp #{resp.status}, #{resp.header}"
|
70
|
-
break unless req.keep_alive?
|
71
|
-
end
|
72
|
-
rescue StandardError => e
|
73
|
-
STDERR.puts "Error in request handling #{e}"
|
74
|
-
STDERR.puts e.backtrace
|
75
|
-
end
|
76
|
-
s.close
|
77
|
-
end
|
78
|
-
end
|
79
|
-
end
|
80
|
-
|
81
|
-
def self.set_error(resp, error)
|
82
|
-
STDERR.puts "Error in function: \"#{error}\""
|
83
|
-
STDERR.puts error.backtrace
|
84
|
-
|
85
|
-
resp["content-type"] = "application/json"
|
86
|
-
resp.status = 502
|
87
|
-
resp.body = { message: "An error occurred in the function",
|
88
|
-
detail: error.to_s }.to_json
|
89
|
-
end
|
90
|
-
private_class_method :set_error
|
91
|
-
|
92
|
-
def self.handle_call(target, req, resp)
|
93
|
-
headers = {}
|
94
|
-
req.header.map do |k, v|
|
95
|
-
headers[k] = v unless @filter_headers.include? k
|
96
|
-
end
|
97
|
-
|
98
|
-
headers_out_hash = {}
|
99
|
-
headers_out = FDK::OutHeaders.new(headers_out_hash, nil)
|
100
|
-
headers_in = FDK::InHeaders.new(headers, nil)
|
101
|
-
context = FDK::Context.new(headers_in, headers_out)
|
102
|
-
input = ParsedInput.new(raw_input: req.body.to_s)
|
103
|
-
|
104
|
-
begin
|
105
|
-
rv = if target.respond_to? :call
|
106
|
-
target.call(context: context, input: input.parsed)
|
107
|
-
else
|
108
|
-
send(target, context: context, input: input.parsed)
|
109
|
-
end
|
110
|
-
rescue StandardError => e
|
111
|
-
set_error(resp, e)
|
112
|
-
return
|
113
|
-
end
|
114
|
-
|
115
|
-
resp.status = 200
|
116
|
-
headers_out_hash.map do |k, v|
|
117
|
-
resp[k] = v.join(",") unless @filter_headers.include? k
|
118
|
-
end
|
119
|
-
|
120
|
-
# TODO: gimme a bit me flexibility on response handling
|
121
|
-
# binary, streams etc
|
122
|
-
if !rv.nil? && rv.respond_to?("to_json")
|
123
|
-
resp.body = rv.to_json
|
124
|
-
# don't override content type if already set
|
125
|
-
resp["content-type"] = "application/json" unless resp["content-type"]
|
126
|
-
else
|
127
|
-
resp.body = rv.to_s
|
128
|
-
end
|
129
|
-
end
|
130
|
-
|
131
|
-
# Stores raw input and can parse it as
|
132
|
-
# JSON (add extra formats as required)
|
133
|
-
class ParsedInput
|
134
|
-
attr_reader :raw
|
135
|
-
|
136
|
-
def initialize(raw_input:)
|
137
|
-
@raw = raw_input
|
138
|
-
end
|
139
|
-
|
140
|
-
def as_json
|
141
|
-
@json ||= JSON.parse(raw)
|
142
|
-
rescue JSON::ParserError
|
143
|
-
@json = false
|
144
|
-
end
|
145
|
-
|
146
|
-
def parsed
|
147
|
-
as_json || raw
|
17
|
+
func = Function.new(function: target, format: ENV["FN_FORMAT"])
|
18
|
+
Listener.new(url: ENV["FN_LISTENER"]).listen do |req, resp|
|
19
|
+
func.call(request: req, response: resp)
|
148
20
|
end
|
149
21
|
end
|
150
22
|
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
module FDK
|
2
|
+
# ParsedInput stores raw input and can parse it as
|
3
|
+
# JSON (add extra formats as required)
|
4
|
+
class ParsedInput
|
5
|
+
attr_reader :raw
|
6
|
+
|
7
|
+
def initialize(raw_input:)
|
8
|
+
@raw = raw_input
|
9
|
+
end
|
10
|
+
|
11
|
+
def as_json
|
12
|
+
@json ||= JSON.parse(raw)
|
13
|
+
rescue JSON::ParserError
|
14
|
+
@json = false
|
15
|
+
end
|
16
|
+
|
17
|
+
def parsed
|
18
|
+
as_json || raw
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
data/lib/fdk/version.rb
CHANGED
data/lib/fdk.rb
CHANGED
@@ -1,3 +1,7 @@
|
|
1
|
-
require_relative
|
2
|
-
require_relative
|
3
|
-
require_relative
|
1
|
+
require_relative "fdk/version"
|
2
|
+
require_relative "fdk/runner"
|
3
|
+
require_relative "fdk/context"
|
4
|
+
require_relative "fdk/call"
|
5
|
+
require_relative "fdk/listener"
|
6
|
+
require_relative "fdk/function"
|
7
|
+
require_relative "fdk/support_classes"
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: fdk
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.15
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Travis Reeder
|
@@ -10,7 +10,7 @@ authors:
|
|
10
10
|
autorequire:
|
11
11
|
bindir: bin
|
12
12
|
cert_chain: []
|
13
|
-
date: 2018-10-
|
13
|
+
date: 2018-10-29 00:00:00.000000000 Z
|
14
14
|
dependencies:
|
15
15
|
- !ruby/object:Gem::Dependency
|
16
16
|
name: json
|
@@ -65,8 +65,12 @@ files:
|
|
65
65
|
- README.md
|
66
66
|
- Rakefile
|
67
67
|
- lib/fdk.rb
|
68
|
+
- lib/fdk/call.rb
|
68
69
|
- lib/fdk/context.rb
|
70
|
+
- lib/fdk/function.rb
|
71
|
+
- lib/fdk/listener.rb
|
69
72
|
- lib/fdk/runner.rb
|
73
|
+
- lib/fdk/support_classes.rb
|
70
74
|
- lib/fdk/version.rb
|
71
75
|
homepage: https://github.com/fnproject/fdk-ruby
|
72
76
|
licenses:
|
@@ -88,7 +92,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
88
92
|
version: '0'
|
89
93
|
requirements: []
|
90
94
|
rubyforge_project:
|
91
|
-
rubygems_version: 2.
|
95
|
+
rubygems_version: 2.6.14.1
|
92
96
|
signing_key:
|
93
97
|
specification_version: 4
|
94
98
|
summary: Ruby FDK for Fn Project
|