toycol 0.3.0 → 0.3.1

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: a9cd0de8dd5ec5a48e22a49c8198492a96162c9ff922a07c897e3af7cdfe779a
4
- data.tar.gz: 938b7f68fef82731d61c1937c2ed53753c1bbb301c49434cc6d538edb6f862f9
3
+ metadata.gz: 94c69c1ed2726e69431304ff3c4fb727581b7893160d5dbe085731f4d85dfce2
4
+ data.tar.gz: 94fc2c13fbd5149a47669a521dfa40377e1edf890a92b33468bf534c6d34ed45
5
5
  SHA512:
6
- metadata.gz: 53e62c64e3f418da9e0f7068482531bab41466e6d73d560e8bf74ae900cf2587a61d810365eea15f01f194592c70b563320ffe93f170810e4fa6f443f3a73837
7
- data.tar.gz: 112910c06cdb28e5f8690fd18373a2d418a466b075cc0ff793816aed2475acb1ccf5657ae8cfb7b3c321cefc1bde44e5a34fd9b9024f3c20d14047938adf6121
6
+ metadata.gz: c5c3d01ea2c3b41491e3d365b781d92677ef027ce9fefa1d45b3ab360e947416035c39d5c9d32dd29ae01c309dfa27338097e5a63dfcd248aa9647b45784bb28
7
+ data.tar.gz: d09afa0497d2b40fcc0b404a19ceee343b9f132a434cbf80feef1cac3bbef060397bccc15503beb507be6e0b03d33b6d5f5cdbe96c5499a093b3a8a27dbd8f24
@@ -1,11 +1,12 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require "rack"
4
3
  require "rack/handler"
5
4
 
6
5
  module Rack
7
6
  module Handler
8
7
  class Toycol
8
+ extend ::Toycol::Helper
9
+
9
10
  class << self
10
11
  attr_writer :preferred_background_server, :host, :port
11
12
 
@@ -27,20 +28,20 @@ module Rack
27
28
  def select_background_server
28
29
  case @preferred_background_server
29
30
  when "puma"
30
- return "puma" if puma_requireable?
31
+ return "puma" if try_require_puma_handler
31
32
 
32
33
  raise LoadError, "Puma is not installed in your environment."
33
34
  when nil
34
- puma_requireable? ? "puma" : "build_in"
35
+ try_require_puma_handler ? "puma" : "builtin"
35
36
  else
36
- "build_in"
37
+ "builtin"
37
38
  end
38
39
  rescue LoadError
39
40
  Process.kill(:INT, Process.ppid)
40
41
  abort
41
42
  end
42
43
 
43
- def puma_requireable?
44
+ def try_require_puma_handler
44
45
  require "rack/handler/puma"
45
46
  true
46
47
  rescue LoadError
@@ -50,10 +51,10 @@ module Rack
50
51
  def run_background_server
51
52
  case select_background_server
52
53
  when "puma"
53
- puts "Toycol starts Puma in single mode, listening on unix://#{::Toycol::UNIX_SOCKET_PATH}"
54
+ logger "Start Puma in single mode, listening on unix://#{::Toycol::UNIX_SOCKET_PATH}"
54
55
  Rack::Handler::Puma.run(@app, **{ Host: ::Toycol::UNIX_SOCKET_PATH, Silent: true })
55
56
  else
56
- puts "Toycol starts build-in server, listening on unix://#{::Toycol::UNIX_SOCKET_PATH}"
57
+ logger "Start built-in server, listening on unix://#{::Toycol::UNIX_SOCKET_PATH}"
57
58
  ::Toycol::Server.run(@app, **{ Path: ::Toycol::UNIX_SOCKET_PATH, Port: @port })
58
59
  end
59
60
  end
data/lib/toycol.rb CHANGED
@@ -1,27 +1,33 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require "fileutils"
4
+ require "optparse"
5
+ require "rack"
6
+ require "socket"
7
+ require "stringio"
4
8
 
5
9
  require_relative "toycol/const"
6
10
  require_relative "toycol/helper"
7
11
  require_relative "toycol/protocol"
8
12
  require_relative "toycol/proxy"
9
13
  require_relative "toycol/server"
10
- require_relative "rack/handler/toycol"
11
-
12
- Dir["#{FileUtils.pwd}/Protocolfile*"].sort.each { |f| load f }
13
-
14
+ require_relative "toycol/client"
15
+ require_relative "toycol/template_generator"
14
16
  require_relative "toycol/command"
15
17
  require_relative "toycol/version"
16
18
 
19
+ require_relative "rack/handler/toycol"
20
+
17
21
  module Toycol
18
22
  class Error < StandardError; end
19
23
 
20
- class UnauthorizedMethodError < Error; end
24
+ class UnauthorizeError < Error; end
21
25
 
22
- class UnauthorizedRequestError < Error; end
26
+ class UndefinementError < Error; end
23
27
 
24
- class UndefinedRequestMethodError < Error; end
28
+ class DuplicateProtocolError < Error; end
25
29
 
26
- class UnknownStatusCodeError < Error; end
30
+ class HTTPError < Error; end
27
31
  end
32
+
33
+ Dir["#{FileUtils.pwd}/Protocolfile*"].sort.each { |f| load f }
data/lib/toycol/client.rb CHANGED
@@ -1,19 +1,20 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require "socket"
4
-
5
3
  module Toycol
6
4
  class Client
5
+ extend Helper
6
+
7
7
  @port = 9292
8
+ @host = "localhost"
8
9
  CHUNK_SIZE = 1024 * 16
9
10
 
10
11
  class << self
11
- attr_writer :port
12
+ attr_writer :port, :host
12
13
 
13
14
  def execute!(request_message, &block)
14
- socket = TCPSocket.new("localhost", @port)
15
+ socket = TCPSocket.new(@host, @port)
15
16
  socket.write(request_message)
16
- puts "[Toycol] Sent request message: #{request_message}\n---"
17
+ logger "Sent request message: #{request_message}\n---"
17
18
 
18
19
  response_message = []
19
20
  response_message << socket.readpartial(CHUNK_SIZE) until socket.eof?
@@ -29,7 +30,7 @@ module Toycol
29
30
 
30
31
  def default_proc
31
32
  proc do |message|
32
- puts "[Toycol] Received response message:\n\n"
33
+ logger "Received response message:\n\n"
33
34
  puts message
34
35
  end
35
36
  end
@@ -1,9 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require "optparse"
4
- require_relative "./client"
5
- require_relative "./template_generator"
6
-
7
3
  module Toycol
8
4
  class Command
9
5
  class Options
@@ -81,8 +77,13 @@ module Toycol
81
77
 
82
78
  def client_option_parser
83
79
  OptionParser.new do |opt|
84
- opt.on("-p PORT_NUMBER", "--port PORT_NUMBER", "listen on PORT (default: 9292)") do |port|
85
- ::Toycol::Client.port = port
80
+ opt.banner = "Usage: #{opt.program_name} client [-h|--help] REQUEST_MESSAGE [arg...]"
81
+ opt.on("-o HOST", "--host HOST", "connect to HOST (default: localhost)") do |host|
82
+ Client.host = host
83
+ end
84
+
85
+ opt.on("-p PORT_NUMBER", "--port PORT_NUMBER", "connect to PORT (default: 9292)") do |port|
86
+ Client.port = port
86
87
  end
87
88
 
88
89
  opt.on_head("-h", "--help", "Show this message") { help_command(opt) }
@@ -91,6 +92,7 @@ module Toycol
91
92
 
92
93
  def server_option_parser
93
94
  OptionParser.new do |opt|
95
+ opt.banner = "Usage: #{opt.program_name} server [-h|--help] APPLICATION_PATH [arg...]"
94
96
  opt.on("-o HOST", "--host HOST", "bind to HOST (default: localhost)") do |host|
95
97
  ::Rack::Handler::Toycol.host = host
96
98
  end
@@ -99,7 +101,7 @@ module Toycol
99
101
  ::Rack::Handler::Toycol.port = port
100
102
  end
101
103
 
102
- opt.on("-u SERVER_NAME", "--use SERVER_NAME", "switch using SERVER(puma/build_in)") do |server_name|
104
+ opt.on("-u SERVER_NAME", "--use SERVER_NAME", "switch using SERVER(puma/builtin)") do |server_name|
103
105
  ::Rack::Handler::Toycol.preferred_background_server = server_name
104
106
  end
105
107
 
@@ -138,13 +140,13 @@ module Toycol
138
140
 
139
141
  case command
140
142
  when "client", "c"
141
- ::Toycol::Client.execute!(options[:request_message])
143
+ Client.execute!(options[:request_message])
142
144
  when "server", "s"
143
145
  ARGV.push("-q", "-s", "toycol")
144
146
  Rack::Server.start
145
147
  when "generate", "g"
146
148
  type = options[:template_type] || "all"
147
- ::Toycol::TemplateGenerator.generate!(type: type, name: options[:protocol_name])
149
+ TemplateGenerator.generate!(type: type, name: options[:protocol_name])
148
150
  end
149
151
  end
150
152
  end
data/lib/toycol/helper.rb CHANGED
@@ -2,6 +2,10 @@
2
2
 
3
3
  module Toycol
4
4
  module Helper
5
+ def logger(message)
6
+ puts "[Toycol] #{message}"
7
+ end
8
+
5
9
  private
6
10
 
7
11
  def safe_execution!(&block)
@@ -10,8 +14,8 @@ module Toycol
10
14
 
11
15
  def safe_executionable_tp
12
16
  @safe_executionable_tp ||= TracePoint.new(:script_compiled) do |tp|
13
- if tp.binding.receiver == Toycol::Protocol && tp.method_id.to_s.match?(unauthorized_methods_regex)
14
- raise Toycol::UnauthorizedMethodError, <<~ERROR
17
+ if tp.binding.receiver == Protocol && tp.method_id.to_s.match?(unauthorized_methods_regex)
18
+ raise UnauthorizeError, <<~ERROR
15
19
  - Unauthorized method was called!
16
20
  You can't use methods that may cause injections in your protocol.
17
21
  Ex. Kernel.#eval, Kernel.#exec, Kernel.#require and so on.
@@ -5,23 +5,30 @@ module Toycol
5
5
  class Protocol
6
6
  @definements = {}
7
7
  @protocol_name = nil
8
- @http_status_codes = Toycol::DEFAULT_HTTP_STATUS_CODES.dup
9
- @http_request_methods = Toycol::DEFAULT_HTTP_REQUEST_METHODS.dup
8
+ @http_status_codes = DEFAULT_HTTP_STATUS_CODES.dup
9
+ @http_request_methods = DEFAULT_HTTP_REQUEST_METHODS.dup
10
10
  @custom_status_codes = nil
11
11
  @additional_request_methods = nil
12
12
 
13
13
  class << self
14
- # For protocol definition
15
- def define(protocol_name = nil, &block)
14
+ attr_reader :protocol_name
15
+
16
+ # For Protocolfile to define new protocol
17
+ def define(protocol_name = :default, &block)
18
+ if @definements[protocol_name]
19
+ raise DuplicateProtocolError,
20
+ "#{protocol_name || "Anonymous"} protocol has already been defined"
21
+ end
22
+
16
23
  @definements[protocol_name] = block
17
24
  end
18
25
 
19
- # For application which use the protocol
20
- def use(protocol_name = nil)
26
+ # For application to select which protocol to use
27
+ def use(protocol_name = :default)
21
28
  @protocol_name = protocol_name
22
29
  end
23
30
 
24
- # For server which use the protocol
31
+ # For proxy server to interpret protocol definitions and parse messages
25
32
  def run!(message)
26
33
  @request_message = message.chomp
27
34
 
@@ -67,52 +74,54 @@ module Toycol
67
74
  end
68
75
  end
69
76
 
70
- # For server: Get the request path
77
+ # For proxy server: Fetch the request path
71
78
  def request_path
72
79
  request_path = request.instance_variable_get("@path").call(request_message)
73
80
 
74
- raise UnauthorizedRequestError, "This request path is too long" if request_path.size >= 2048
75
-
76
- if request_path.scan(%r{[/\w\d\-_]}).size < request_path.size
77
- raise UnauthorizedRequestError,
81
+ if request_path.size >= 2048
82
+ raise UnauthorizeError,
83
+ "This request path is too long"
84
+ elsif request_path.scan(%r{[/\w\d\-_]}).size < request_path.size
85
+ raise UnauthorizeError,
78
86
  "This request path contains unauthorized character"
79
87
  end
80
88
 
81
89
  request_path
82
90
  end
83
91
 
84
- # For server: Get the request method
92
+ # For proxy server: Fetch the request method
85
93
  def request_method
86
94
  @http_request_methods.concat @additional_request_methods if @additional_request_methods
87
95
  request_method = request.instance_variable_get("@http_method").call(request_message)
88
96
 
89
97
  unless @http_request_methods.include? request_method
90
- raise UndefinedRequestMethodError, "This request method is undefined"
98
+ raise UndefinementError,
99
+ "This request method is undefined"
91
100
  end
92
101
 
93
102
  request_method
94
103
  end
95
104
 
96
- # For server: Get the query string
105
+ # For proxy server: Fetch the query string
97
106
  def query
98
107
  return unless (parse_query_block = request.instance_variable_get("@query"))
99
108
 
100
109
  parse_query_block.call(request_message)
101
110
  end
102
111
 
103
- # For server: Get the input body
112
+ # For proxy server: Fetch the input body
104
113
  def input
105
114
  return unless (parsed_input_block = request.instance_variable_get("@input"))
106
115
 
107
116
  parsed_input_block.call(request_message)
108
117
  end
109
118
 
110
- # For server: Get the message of status code
119
+ # For proxy server: fetch the message of status code
111
120
  def status_message(status)
112
121
  @http_status_codes.merge!(@custom_status_codes) if @custom_status_codes
113
122
 
114
123
  unless (message = @http_status_codes[status])
115
- raise UnknownStatusCodeError, "Application returns unknown status code"
124
+ raise HTTPError, "Application returns unknown status code"
116
125
  end
117
126
 
118
127
  message
data/lib/toycol/proxy.rb CHANGED
@@ -1,7 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require "socket"
4
-
5
3
  module Toycol
6
4
  class Proxy
7
5
  include Helper
@@ -13,15 +11,15 @@ module Toycol
13
11
  @path = nil
14
12
  @query = nil
15
13
  @input = nil
16
- @protocol = ::Toycol::Protocol
14
+ @protocol = Protocol
17
15
  @proxy = TCPServer.new(@host, @port)
18
16
  end
19
17
 
20
18
  CHUNK_SIZE = 1024 * 16
21
19
 
22
20
  def start
23
- puts <<~MESSAGE
24
- Toycol is running on #{@host}:#{@port}
21
+ logger <<~MESSAGE
22
+ Start proxy server on #{@protocol.protocol_name} protocol, listening on #{@host}:#{@port}
25
23
  => Use Ctrl-C to stop
26
24
  MESSAGE
27
25
 
@@ -33,13 +31,13 @@ module Toycol
33
31
  while !@client.closed? && !@client.eof?
34
32
  begin
35
33
  request = @client.readpartial(CHUNK_SIZE)
36
- puts "[Toycol] Received message: #{request.inspect.chomp}"
34
+ logger "Received message: #{request.inspect.chomp}"
37
35
 
38
36
  safe_execution! { @protocol.run!(request) }
39
37
  assign_parsed_attributes!
40
38
 
41
39
  http_request_message = build_http_request_message
42
- puts "[Toycol] Message has been translated to HTTP request message: #{http_request_message.inspect}"
40
+ logger "Message has been translated to HTTP request message: #{http_request_message.inspect}"
43
41
  transfer_to_server(http_request_message)
44
42
  rescue StandardError => e
45
43
  puts "#{e.class} #{e.message} - closing socket."
@@ -82,15 +80,15 @@ module Toycol
82
80
  end
83
81
 
84
82
  def transfer_to_server(request_message)
85
- UNIXSocket.open(Toycol::UNIX_SOCKET_PATH) do |server|
83
+ UNIXSocket.open(UNIX_SOCKET_PATH) do |server|
86
84
  server.write request_message
87
85
  server.close_write
88
- puts "[Toycol] Successed to Send HTTP request message to server"
86
+ logger "Successed to Send HTTP request message to server"
89
87
 
90
88
  response_message = []
91
89
  response_message << server.readpartial(CHUNK_SIZE) until server.eof?
92
90
  response_message = response_message.join
93
- puts "[Toycol] Received response message from server: #{response_message.lines.first}"
91
+ logger "Received response message from server: #{response_message.lines.first}"
94
92
 
95
93
  response_line = response_message.lines.first
96
94
  status_number = response_line[9..11]
@@ -98,18 +96,18 @@ module Toycol
98
96
 
99
97
  if (custom_message = @protocol.status_message(status_number.to_i)) != status_message
100
98
  response_message = response_message.sub(status_message, custom_message)
101
- puts "[Toycol] Status message has been translated to custom status message: #{custom_message}"
99
+ logger "Status message has been translated to custom status message: #{custom_message}"
102
100
  end
103
101
 
104
102
  @client.write response_message
105
103
  @client.close_write
106
- puts "[Toycol] Finished to response to client"
104
+ logger "Finished to response to client"
107
105
  server.close
108
106
  end
109
107
  end
110
108
 
111
109
  def shutdown
112
- puts "[Toycol] Catched SIGINT -> Stop to server"
110
+ logger "Caught SIGINT -> Stop to server"
113
111
  exit
114
112
  end
115
113
  end
data/lib/toycol/server.rb CHANGED
@@ -1,7 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require "stringio"
4
-
5
3
  module Toycol
6
4
  class Server
7
5
  BACKLOG = 1024
@@ -50,19 +48,19 @@ module Toycol
50
48
 
51
49
  def default_env
52
50
  {
53
- ::Toycol::PATH_INFO => "",
54
- ::Toycol::QUERY_STRING => "",
55
- ::Toycol::REQUEST_METHOD => "",
56
- ::Toycol::SERVER_NAME => "toycol_server",
57
- ::Toycol::SERVER_PORT => @port.to_s,
58
- ::Toycol::CONTENT_LENGTH => "0",
59
- ::Toycol::RACK_VERSION => Rack::VERSION,
60
- ::Toycol::RACK_INPUT => stringio(""),
61
- ::Toycol::RACK_ERRORS => $stderr,
62
- ::Toycol::RACK_MULTITHREAD => false,
63
- ::Toycol::RACK_MULTIPROCESS => false,
64
- ::Toycol::RACK_RUN_ONCE => false,
65
- ::Toycol::RACK_URL_SCHEME => "http"
51
+ PATH_INFO => "",
52
+ QUERY_STRING => "",
53
+ REQUEST_METHOD => "",
54
+ SERVER_NAME => "toycol_server",
55
+ SERVER_PORT => @port.to_s,
56
+ CONTENT_LENGTH => "0",
57
+ RACK_VERSION => Rack::VERSION,
58
+ RACK_INPUT => stringio(""),
59
+ RACK_ERRORS => $stderr,
60
+ RACK_MULTITHREAD => false,
61
+ RACK_MULTIPROCESS => false,
62
+ RACK_RUN_ONCE => false,
63
+ RACK_URL_SCHEME => "http"
66
64
  }
67
65
  end
68
66
 
@@ -71,7 +69,7 @@ module Toycol
71
69
  end
72
70
 
73
71
  def response_status_code
74
- "HTTP/1.1 #{@returned_status} #{::Toycol::DEFAULT_HTTP_STATUS_CODES[@returned_status.to_i] || "CUSTOM"}\r\n"
72
+ "HTTP/1.1 #{@returned_status} #{DEFAULT_HTTP_STATUS_CODES[@returned_status.to_i] || "CUSTOM"}\r\n"
75
73
  end
76
74
 
77
75
  def response_headers
@@ -108,17 +106,17 @@ module Toycol
108
106
  request_method, request_path, = request_line.split
109
107
  request_path, query_string = request_path.split("?")
110
108
 
111
- @env[::Toycol::REQUEST_METHOD] = request_method
112
- @env[::Toycol::PATH_INFO] = request_path
113
- @env[::Toycol::QUERY_STRING] = query_string || ""
114
- @env[::Toycol::CONTENT_LENGTH]
109
+ @env[REQUEST_METHOD] = request_method
110
+ @env[PATH_INFO] = request_path
111
+ @env[QUERY_STRING] = query_string || ""
112
+ @env[CONTENT_LENGTH]
115
113
 
116
114
  request_headers.each do |request_header|
117
115
  k, v = request_header.split(":").map(&:strip)
118
- @env["::Toycol::#{k.tr("-", "_").upcase}"] = v
116
+ @env[k.tr("-", "_").upcase.to_s] = v
119
117
  end
120
118
 
121
- @env[::Toycol::RACK_INPUT] = stringio(request_body)
119
+ @env[RACK_INPUT] = stringio(request_body)
122
120
  end
123
121
  end
124
122
  end
@@ -2,9 +2,11 @@
2
2
 
3
3
  module Toycol
4
4
  class TemplateGenerator
5
+ include Helper
6
+
5
7
  class << self
6
8
  def generate!(type:, name:)
7
- raise StandardError, "Unknown Type: This type of template can't be generated" unless valid? type
9
+ raise Error, "Unknown Type: This type of template can't be generated" unless valid? type
8
10
 
9
11
  if type == "all"
10
12
  new(name, "protocol").generate!
@@ -27,10 +29,10 @@ module Toycol
27
29
  end
28
30
 
29
31
  def generate!
30
- raise StandardError, "#{filename} already exists" unless Dir.glob(filename).empty?
32
+ raise Error, "#{filename} already exists" unless Dir.glob(filename).empty?
31
33
 
32
34
  File.open(filename, "w") { |f| f.print template_text_for_new }
33
- puts "Generate #{filename} in #{FileUtils.pwd}"
35
+ logger "Generate #{filename} in #{FileUtils.pwd}"
34
36
  end
35
37
 
36
38
  private
@@ -52,8 +54,8 @@ module Toycol
52
54
 
53
55
  def template_text
54
56
  case @type
55
- when "protocol" then File.open("lib/toycol/templates/protocol.txt", "r", &:read)
56
- when "app" then File.open("lib/toycol/templates/application.txt", "r", &:read)
57
+ when "protocol" then File.open("#{__dir__}/templates/protocol.txt", "r", &:read)
58
+ when "app" then File.open("#{__dir__}/templates/application.txt", "r", &:read)
57
59
  end
58
60
  end
59
61
  end
@@ -1,19 +1,24 @@
1
1
  require "rack"
2
2
  require "toycol"
3
3
 
4
- # Specify which protocol to use
5
4
  Toycol::Protocol.use(:PROTOCOL_NAME)
6
5
 
7
6
  class App
8
7
  def call(env)
9
8
  # Define your app on request method, request path, request query etc
10
9
  # For example:
11
- # case env['REQUEST_METHOD']
12
- # when 'GET'
10
+ # case env["REQUEST_METHOD"]
11
+ # when "GET"
13
12
  # [
14
13
  # 200,
15
- # { 'Content-Type' => 'text/html' },
16
- # ["Hello, This app is running by :#{name} protocol."]
14
+ # { "Content-Type" => "text/html" },
15
+ # ["Hello, This app is running by new protocol."]
16
+ # ]
17
+ # when "OTHER"
18
+ # [
19
+ # 600,
20
+ # { "Content-Type" => "text/html" },
21
+ # ["This is response message for additional request method"]
17
22
  # ]
18
23
  # end
19
24
  end
@@ -8,11 +8,11 @@ Toycol::Protocol.define(:PROTOCOL_NAME) do
8
8
 
9
9
  # [OPTIONAL] You can define your additional request methods:
10
10
  # For example:
11
- # additional_request_methods OTHER
11
+ # additional_request_methods "OTHER"
12
12
 
13
13
  # [OPTIONAL] You can define your own response status code:
14
14
  # For example:
15
- # define_status_codes(
15
+ # custom_status_codes(
16
16
  # 600 => "I'm afraid you are not a duck..."
17
17
  # )
18
18
 
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Toycol
4
- VERSION = "0.3.0"
4
+ VERSION = "0.3.1"
5
5
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: toycol
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.0
4
+ version: 0.3.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Misaki Shioi
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2021-07-25 00:00:00.000000000 Z
11
+ date: 2021-07-27 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rack