file_sv 0.1.1 → 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/exe/file_sv +12 -4
- data/lib/file_sv.rb +34 -13
- data/lib/file_sv/file_processor.rb +2 -1
- data/lib/file_sv/file_sv.ico +0 -0
- data/lib/file_sv/global_settings.rb +38 -0
- data/lib/file_sv/planned_endpoint.rb +14 -6
- data/lib/file_sv/service_loader.rb +9 -1
- data/lib/file_sv/sv_plan.rb +36 -14
- data/lib/file_sv/version.rb +1 -1
- data/lib/file_sv/virtual_server.rb +79 -9
- data/lib/file_sv/yaml_processor.rb +7 -1
- metadata +18 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: a6fe6c5fff5f5d93506024349027d89d5ae0331b22f1dc15c94aaf72b18d1c8a
|
4
|
+
data.tar.gz: b8c7f47b3602949beb64b5b7e9fa7f859b2fc3020f5c1a3d91fa9a6309a1ad8a
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 3b6521770efbd56f4b790650de3801668e80b4c197e995d3cdd1a97326013c58e241d265caf1735eeeae020050aa775ad44d7acb29b0c651aa3401b109bd7be0
|
7
|
+
data.tar.gz: ac3d6a6d948161f2b96f38090a148e3605927a9a43a690a05933b3a942905903f1c95b9e84ead1a204441b7edd66ef179be8aac3e30d6ddb2946a0330314d195
|
data/exe/file_sv
CHANGED
@@ -12,16 +12,24 @@ class Exe < Thor
|
|
12
12
|
ServiceLoader.create_plan_for folder
|
13
13
|
end
|
14
14
|
|
15
|
+
option :crt, default: nil, banner: "HTTPS CRT"
|
16
|
+
option :key, default: nil, banner: "HTTPS key"
|
15
17
|
desc "serve folder", "Serve virtual service based on folder"
|
16
18
|
def serve(folder)
|
17
19
|
plan folder
|
18
|
-
ServiceLoader.serve_plan
|
20
|
+
ServiceLoader.serve_plan options
|
19
21
|
end
|
20
22
|
|
21
|
-
desc "
|
22
|
-
def
|
23
|
+
desc "inspect folder", "Inspect details of what's served at folder"
|
24
|
+
def inspect(folder)
|
23
25
|
require "file_sv"
|
24
|
-
|
26
|
+
ServiceLoader.inspect folder
|
27
|
+
end
|
28
|
+
|
29
|
+
desc "version", "Version of FileSv"
|
30
|
+
def version
|
31
|
+
require "file_sv/version"
|
32
|
+
puts "FileSv version #{FileSv::VERSION}"
|
25
33
|
end
|
26
34
|
end
|
27
35
|
|
data/lib/file_sv.rb
CHANGED
@@ -1,5 +1,6 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
require "yaml"
|
3
4
|
require_relative "file_sv/version"
|
4
5
|
require_relative "file_sv/global_settings"
|
5
6
|
require_relative "file_sv/sv_plan"
|
@@ -15,29 +16,49 @@ module FileSv
|
|
15
16
|
class FileNameError < Error; end
|
16
17
|
|
17
18
|
class << self
|
19
|
+
# @return [Hash] Mapping of REST method names to setting classes
|
18
20
|
def rest_methods
|
19
21
|
{
|
20
22
|
get: GetSettings, post: PostSettings, patch: PatchSettings, options: OptionsSettings,
|
21
|
-
delete: DeleteSettings
|
23
|
+
delete: DeleteSettings, put: PutSettings
|
22
24
|
}
|
23
25
|
end
|
24
26
|
end
|
25
27
|
end
|
26
28
|
|
27
|
-
require "yaml"
|
28
29
|
CONFIG_FILE = "file_sv.yaml"
|
29
|
-
if File.exist? CONFIG_FILE
|
30
|
-
# Set values in global settings based on config
|
31
|
-
class GlobalSettings
|
32
|
-
config = YAML.load_file CONFIG_FILE
|
33
|
-
config["global"]&.each do |key, value|
|
34
|
-
send("#{key}=", value)
|
35
|
-
end
|
36
30
|
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
31
|
+
# Set values in global settings based on config
|
32
|
+
def load_default_config(file_path)
|
33
|
+
return unless File.exist? file_path
|
34
|
+
|
35
|
+
config = YAML.load_file file_path
|
36
|
+
return unless config # Handle empty YAML file
|
37
|
+
|
38
|
+
config["global"]&.each do |key, value|
|
39
|
+
GlobalSettings.send("#{key}=", value)
|
40
|
+
end
|
41
|
+
|
42
|
+
load_rest_method_config config
|
43
|
+
end
|
44
|
+
|
45
|
+
# Load details of each REST method
|
46
|
+
def load_rest_method_config(config)
|
47
|
+
FileSv.rest_methods.each do |method, setting_class|
|
48
|
+
config[method.to_s]&.each { |key, value| setting_class.send("#{key}=", value) }
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
# Set global params based on ENV vars
|
53
|
+
def set_based_on_env_vars
|
54
|
+
GlobalSettings.instance_variables.each do |setting|
|
55
|
+
setting_name = setting.to_s[1..-1]
|
56
|
+
if ENV[setting_name]
|
57
|
+
puts "Setting #{setting_name} to #{ENV[setting_name]}"
|
58
|
+
GlobalSettings.send("#{setting_name}=", ENV[setting_name])
|
41
59
|
end
|
42
60
|
end
|
43
61
|
end
|
62
|
+
|
63
|
+
load_default_config CONFIG_FILE
|
64
|
+
set_based_on_env_vars
|
@@ -6,7 +6,8 @@ class FileProcessor
|
|
6
6
|
class << self
|
7
7
|
# Process file, adding it to plan
|
8
8
|
def process(filename)
|
9
|
-
|
9
|
+
endpoint = PlannedEndpoint.new(filename)
|
10
|
+
SvPlan + endpoint unless GlobalSettings.ignored_status? endpoint.status_code
|
10
11
|
end
|
11
12
|
end
|
12
13
|
end
|
Binary file
|
@@ -5,14 +5,46 @@ class GlobalSettings
|
|
5
5
|
@default_method = "get"
|
6
6
|
|
7
7
|
@empty_body_status = 204
|
8
|
+
|
9
|
+
@ignore_files = "{*.md,Dockerfile,.*}"
|
10
|
+
|
11
|
+
@https = false
|
12
|
+
|
13
|
+
@ignore_status_codes = nil
|
8
14
|
class << self
|
9
15
|
# @return [String] Default REST method when none specified by filename
|
10
16
|
attr_accessor :default_method
|
11
17
|
# @return [Integer] Default status of response when file is empty
|
12
18
|
attr_accessor :empty_body_status
|
19
|
+
# @return [Array] Expression representing files to ignore
|
20
|
+
attr_accessor :ignore_files
|
21
|
+
# @return [Boolean] Whether to serve https using self signed certificate
|
22
|
+
attr_accessor :https
|
23
|
+
# @return [String] Path to HTTPS cert
|
24
|
+
attr_accessor :cert
|
25
|
+
# @return [String] Path to HTTPS key
|
26
|
+
attr_accessor :key
|
27
|
+
# @return [Array] List of http status codes to ignore
|
28
|
+
attr_accessor :ignore_status_codes
|
29
|
+
|
30
|
+
# @param [Integer] status_code HTTP status code
|
31
|
+
# @return [Boolean] Whether status code is currently ignored
|
32
|
+
def ignored_status?(status_code)
|
33
|
+
return unless ignore_status_codes
|
34
|
+
|
35
|
+
ignore_status_codes.split(",").each do |code|
|
36
|
+
regex = Regexp.new code.to_s
|
37
|
+
result = status_code.to_s[regex]
|
38
|
+
next unless result
|
39
|
+
|
40
|
+
return true unless result.empty?
|
41
|
+
end
|
42
|
+
false
|
43
|
+
end
|
13
44
|
end
|
14
45
|
end
|
15
46
|
|
47
|
+
# Http settings that all HTTP method types inherit
|
16
48
|
module CommonHttpSettings
|
17
49
|
attr_accessor :default_status
|
18
50
|
end
|
@@ -35,6 +67,12 @@ class PatchSettings
|
|
35
67
|
extend CommonHttpSettings
|
36
68
|
end
|
37
69
|
|
70
|
+
# Settings specific to PATCH
|
71
|
+
class PutSettings
|
72
|
+
@default_status = 200
|
73
|
+
extend CommonHttpSettings
|
74
|
+
end
|
75
|
+
|
38
76
|
# Settings specific to OPTIONS
|
39
77
|
class OptionsSettings
|
40
78
|
@default_status = 200
|
@@ -3,6 +3,7 @@
|
|
3
3
|
require "erb"
|
4
4
|
require "securerandom"
|
5
5
|
require "faker"
|
6
|
+
require "pathname"
|
6
7
|
|
7
8
|
# Endpoint planned to be served
|
8
9
|
class PlannedEndpoint
|
@@ -16,12 +17,12 @@ class PlannedEndpoint
|
|
16
17
|
attr_accessor :status_code
|
17
18
|
|
18
19
|
# @return [Array]
|
19
|
-
HTTP_METHODS = %w[get post patch delete options].freeze
|
20
|
+
HTTP_METHODS = %w[get put post patch delete options].freeze
|
20
21
|
|
21
22
|
# Represent a new endpoint
|
22
23
|
def initialize(path)
|
23
24
|
self.file_path = path
|
24
|
-
self.path =
|
25
|
+
self.path = serving_loc_for path
|
25
26
|
@file = true if not_text?
|
26
27
|
assign_params_from_name
|
27
28
|
self.method ||= GlobalSettings.default_method
|
@@ -30,21 +31,28 @@ class PlannedEndpoint
|
|
30
31
|
set_default_status_code
|
31
32
|
end
|
32
33
|
|
34
|
+
def serving_loc_for(path)
|
35
|
+
loc = File.split(path).first # TODO: Handle if path has a % at beginning of a folder
|
36
|
+
loc.gsub("#{File::SEPARATOR}%", "#{File::SEPARATOR}:")
|
37
|
+
end
|
38
|
+
|
33
39
|
# @return [Boolean] Whether endpoint serves a file not a string
|
34
40
|
def file?
|
35
41
|
@file
|
36
42
|
end
|
37
43
|
|
44
|
+
# Return default status code for an empty body
|
38
45
|
def default_empty_code
|
39
46
|
return false if not_text?
|
40
47
|
|
41
|
-
if content.strip.empty?
|
48
|
+
if content(binding).strip.empty?
|
42
49
|
self.status_code = GlobalSettings.empty_body_status
|
43
50
|
return true
|
44
51
|
end
|
45
52
|
false
|
46
53
|
end
|
47
54
|
|
55
|
+
# Set default status code based on empty body or type of METHOD
|
48
56
|
def set_default_status_code
|
49
57
|
return if default_empty_code
|
50
58
|
|
@@ -91,8 +99,8 @@ class PlannedEndpoint
|
|
91
99
|
end
|
92
100
|
|
93
101
|
# @return [Object] Content of file
|
94
|
-
def content
|
95
|
-
render_text
|
102
|
+
def content(binding)
|
103
|
+
render_text(binding)
|
96
104
|
end
|
97
105
|
|
98
106
|
def not_text?
|
@@ -101,7 +109,7 @@ class PlannedEndpoint
|
|
101
109
|
end
|
102
110
|
|
103
111
|
# @return [String] Render text
|
104
|
-
def render_text
|
112
|
+
def render_text(binding)
|
105
113
|
ERB.new(File.read(serving_file_name)).result(binding)
|
106
114
|
end
|
107
115
|
end
|
@@ -9,13 +9,21 @@ module ServiceLoader
|
|
9
9
|
# Create virtual service plan based on folder
|
10
10
|
def create_plan_for(folder)
|
11
11
|
SvPlan.create folder
|
12
|
+
puts SvPlan.show
|
13
|
+
end
|
14
|
+
|
15
|
+
# Inspect plan
|
16
|
+
def inspect(folder)
|
17
|
+
create_plan_for folder
|
12
18
|
puts SvPlan.inspect
|
13
19
|
end
|
14
20
|
|
15
21
|
# Serve plan
|
16
|
-
def serve_plan
|
22
|
+
def serve_plan(thor_options)
|
17
23
|
require "sinatra"
|
18
24
|
require_relative "virtual_server"
|
25
|
+
GlobalSettings.key = thor_options[:key] if thor_options[:key]
|
26
|
+
GlobalSettings.cert = thor_options[:crt] if thor_options[:crt]
|
19
27
|
VirtualServer.run!
|
20
28
|
end
|
21
29
|
end
|
data/lib/file_sv/sv_plan.rb
CHANGED
@@ -6,7 +6,7 @@ require_relative "file_processor"
|
|
6
6
|
class SvPlan
|
7
7
|
@endpoints = {}
|
8
8
|
class << self
|
9
|
-
# @return [
|
9
|
+
# @return [Hash] Endpoints included in plan. Key - endpoint, value - methods served under it
|
10
10
|
attr_reader :endpoints
|
11
11
|
# @return [String] Folder plan is served from
|
12
12
|
attr_accessor :serving_folder
|
@@ -15,33 +15,55 @@ class SvPlan
|
|
15
15
|
def create(folder)
|
16
16
|
self.serving_folder = folder
|
17
17
|
puts "Creating service based on files in #{folder}"
|
18
|
-
file_list = Dir.glob("#{folder}/**/*.*")
|
19
|
-
file_list.each
|
20
|
-
process_file file
|
21
|
-
end
|
18
|
+
file_list = Dir.glob("#{folder}/**/*.*") - Dir.glob("#{folder}/#{GlobalSettings.ignore_files}")
|
19
|
+
file_list.each { |file| process_file file }
|
22
20
|
end
|
23
21
|
|
24
|
-
|
25
|
-
|
26
|
-
|
22
|
+
# Process file, for the most part creating endpoint.method from it
|
23
|
+
# @param [String] filename Path to file to process
|
24
|
+
def process_file(filename)
|
25
|
+
filename.slice! serving_folder
|
26
|
+
extension = File.extname(filename)
|
27
27
|
case extension
|
28
|
-
when "yaml" then YamlProcessor.process(
|
28
|
+
when ".yaml" then YamlProcessor.process(filename)
|
29
29
|
else
|
30
|
-
FileProcessor.process(
|
30
|
+
FileProcessor.process(filename)
|
31
31
|
end
|
32
32
|
end
|
33
33
|
|
34
|
-
|
34
|
+
# Show plan
|
35
|
+
def show
|
36
|
+
endpoint_desc = ""
|
37
|
+
endpoints.sort { |a, b| a[0].casecmp b[0] }.each do |endpoint, methods|
|
38
|
+
endpoint_desc += "#{endpoint} \n"
|
39
|
+
methods.each do |method_name, endpoints|
|
40
|
+
endpoint_desc += description_message method_name, endpoints
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
35
44
|
"** VIRTUAL SERVICE PLAN **
|
36
|
-
Serving based on folder: #{serving_folder}
|
37
|
-
|
38
|
-
|
45
|
+
Serving based on folder: #{Dir.pwd}. Related to folder executed: #{serving_folder}
|
46
|
+
#{endpoint_desc}"
|
47
|
+
end
|
48
|
+
|
49
|
+
# Inspect details
|
50
|
+
def inspect
|
51
|
+
"Endpoints: #{endpoints.inspect}"
|
39
52
|
end
|
40
53
|
|
54
|
+
# Add endpoint to plan
|
55
|
+
# @param [PlannedEndpoint] other Endpoint to add to plan
|
41
56
|
def +(other)
|
42
57
|
@endpoints[other.path] ||= {}
|
43
58
|
@endpoints[other.path][other.method] ||= []
|
44
59
|
@endpoints[other.path][other.method] << other
|
45
60
|
end
|
61
|
+
|
62
|
+
private
|
63
|
+
|
64
|
+
# @return [String]
|
65
|
+
def description_message(method_name, endpoints)
|
66
|
+
" #{method_name.upcase} (#{endpoints.size} responses) #{endpoints.collect(&:status_code)}\n"
|
67
|
+
end
|
46
68
|
end
|
47
69
|
end
|
data/lib/file_sv/version.rb
CHANGED
@@ -2,27 +2,97 @@
|
|
2
2
|
|
3
3
|
require "webrick"
|
4
4
|
require "sinatra"
|
5
|
+
require "docdsl"
|
6
|
+
require "webrick/https"
|
7
|
+
require "openssl"
|
5
8
|
|
6
9
|
# Virtual server hosting virtual service defined through files
|
7
10
|
class VirtualServer < Sinatra::Base
|
8
11
|
set :server, "webrick"
|
9
12
|
set :bind, "0.0.0.0"
|
10
13
|
|
14
|
+
register Sinatra::DocDsl
|
15
|
+
|
16
|
+
if GlobalSettings.https
|
17
|
+
def self.own_certs(webrick_options)
|
18
|
+
puts "Using cert from #{GlobalSettings.cert}"
|
19
|
+
cert = OpenSSL::X509::Certificate.new File.read GlobalSettings.cert
|
20
|
+
pkey = OpenSSL::PKey::RSA.new File.read GlobalSettings.key
|
21
|
+
webrick_options[:SSLCertificate] = cert
|
22
|
+
webrick_options[:SSLPrivateKey] = pkey
|
23
|
+
webrick_options
|
24
|
+
end
|
25
|
+
|
26
|
+
def self.determine_certs(webrick_options)
|
27
|
+
if GlobalSettings.key && GlobalSettings.cert
|
28
|
+
webrick_options = own_certs webrick_options
|
29
|
+
else
|
30
|
+
puts "Using self signed cert"
|
31
|
+
webrick_options[:ServerName] = "localhost"
|
32
|
+
webrick_options[:SSLCertName] = "/CN=localhost"
|
33
|
+
end
|
34
|
+
webrick_options
|
35
|
+
end
|
36
|
+
|
37
|
+
# Run as https with self signed cert
|
38
|
+
def self.run!
|
39
|
+
logger = WEBrick::Log.new(nil, WEBrick::BasicLog::WARN)
|
40
|
+
webrick_options = { Port: port, SSLEnable: true, Logger: logger }
|
41
|
+
webrick_options = determine_certs webrick_options
|
42
|
+
# TODO: Following run does not work on Ruby 3
|
43
|
+
Rack::Handler::WEBrick.run(self, webrick_options) do |server|
|
44
|
+
%i[INT TERM].each { |sig| trap(sig) { server.stop } }
|
45
|
+
server.threaded = settings.threaded if server.respond_to? :threaded=
|
46
|
+
set :running, true
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
page do
|
52
|
+
title "File SV"
|
53
|
+
header "Service virtualization created from #{Dir.pwd}"
|
54
|
+
introduction 'Created using file_sv. See <a href="https://gitlab.com/samuel-garratt/file_sv">File SV</a>
|
55
|
+
for more details'
|
56
|
+
end
|
57
|
+
|
58
|
+
get "/favicon.ico" do
|
59
|
+
send_file File.join(__dir__, "file_sv.ico")
|
60
|
+
end
|
61
|
+
|
62
|
+
doc_endpoint "/docs"
|
63
|
+
|
64
|
+
# Output for endpoint, either a file or text content
|
65
|
+
# @param [PlannedEndpoint] endpoint Planned endpoint to serve
|
66
|
+
def output_for(endpoint, binding)
|
67
|
+
endpoint.file? ? send_file(endpoint.serving_file_name) : endpoint.content(binding)
|
68
|
+
end
|
69
|
+
|
70
|
+
# Log endpoint. Return content and status code defined by endpoint
|
71
|
+
# @param [PlannedEndpoint] endpoint Planned endpoint to serve
|
72
|
+
def serve(endpoint, id = nil)
|
73
|
+
message = "Using endpoint based on file #{endpoint.serving_file_name}."
|
74
|
+
@id = id
|
75
|
+
message += " Using param '#{@id}'" if id
|
76
|
+
puts message
|
77
|
+
[endpoint.status_code, output_for(endpoint, binding)]
|
78
|
+
end
|
79
|
+
|
11
80
|
SvPlan.endpoints.each do |_endpoint_path, endpoint_value|
|
12
81
|
endpoint_value.each do |_method_name, endpoints|
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
82
|
+
endpoint_base = endpoints[0]
|
83
|
+
documentation "Endpoint #{endpoint_base.path}" do
|
84
|
+
response "#{endpoints.size} kinds of response"
|
85
|
+
end
|
86
|
+
if endpoint_base.path.include? "#{File::Separator}:"
|
87
|
+
send(endpoint_base.method, endpoint_base.path) do |id|
|
88
|
+
endpoint = endpoints.sample
|
89
|
+
serve endpoint, id
|
17
90
|
end
|
18
91
|
else
|
19
|
-
endpoint_base = endpoints[0]
|
20
92
|
send(endpoint_base.method, endpoint_base.path) do
|
21
|
-
|
22
|
-
endpoint
|
23
|
-
[endpoint.status_code, endpoint.file? ? send_file(endpoint.serving_file_name) : endpoint.content]
|
93
|
+
endpoint = endpoints.sample
|
94
|
+
serve endpoint
|
24
95
|
end
|
25
|
-
# Average same methods at same endpoint
|
26
96
|
end
|
27
97
|
end
|
28
98
|
end
|
@@ -3,8 +3,14 @@
|
|
3
3
|
# Process YAML files
|
4
4
|
class YamlProcessor
|
5
5
|
class << self
|
6
|
+
# Process YAML file
|
6
7
|
def process(filename)
|
7
|
-
|
8
|
+
if filename == "/file_sv.yaml"
|
9
|
+
puts "Overriding default config based on #{File.join(Dir.pwd, filename[1..-1])}"
|
10
|
+
load_default_config filename[1..-1]
|
11
|
+
else
|
12
|
+
puts "Skipping #{filename}"
|
13
|
+
end
|
8
14
|
end
|
9
15
|
end
|
10
16
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: file_sv
|
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
|
- Samuel Garratt
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2021-03-
|
11
|
+
date: 2021-03-14 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: faker
|
@@ -38,6 +38,20 @@ dependencies:
|
|
38
38
|
- - ">="
|
39
39
|
- !ruby/object:Gem::Version
|
40
40
|
version: '0'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: sinatra-docdsl
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - ">="
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '0'
|
48
|
+
type: :runtime
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - ">="
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '0'
|
41
55
|
- !ruby/object:Gem::Dependency
|
42
56
|
name: thor
|
43
57
|
requirement: !ruby/object:Gem::Requirement
|
@@ -79,6 +93,7 @@ files:
|
|
79
93
|
- exe/file_sv
|
80
94
|
- lib/file_sv.rb
|
81
95
|
- lib/file_sv/file_processor.rb
|
96
|
+
- lib/file_sv/file_sv.ico
|
82
97
|
- lib/file_sv/global_settings.rb
|
83
98
|
- lib/file_sv/planned_endpoint.rb
|
84
99
|
- lib/file_sv/render_file.rb
|
@@ -109,7 +124,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
109
124
|
- !ruby/object:Gem::Version
|
110
125
|
version: '0'
|
111
126
|
requirements: []
|
112
|
-
rubygems_version: 3.
|
127
|
+
rubygems_version: 3.1.4
|
113
128
|
signing_key:
|
114
129
|
specification_version: 4
|
115
130
|
summary: REST service virtualisation through file structure.
|