toycol 0.0.1 → 0.2.2

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.
Files changed (38) hide show
  1. checksums.yaml +4 -4
  2. data/.github/ISSUE_TEMPLATE/bug_report.md +29 -0
  3. data/.github/dependabot.yml +9 -0
  4. data/.github/workflows/main.yml +4 -1
  5. data/.gitignore +1 -0
  6. data/.rubocop.yml +26 -1
  7. data/CHANGELOG.md +1 -1
  8. data/README.md +2 -4
  9. data/examples/duck/Gemfile +5 -0
  10. data/examples/duck/Protocolfile.duck +23 -0
  11. data/examples/duck/config_duck.ru +59 -0
  12. data/examples/rubylike/Gemfile +5 -0
  13. data/examples/rubylike/Protocolfile.rubylike +18 -0
  14. data/examples/rubylike/config_rubylike.ru +27 -0
  15. data/examples/safe_ruby/Gemfile +6 -0
  16. data/examples/safe_ruby/Protocolfile.safe_ruby +47 -0
  17. data/examples/safe_ruby/config_safe_ruby.ru +55 -0
  18. data/examples/safe_ruby_with_sinatra/Gemfile +10 -0
  19. data/examples/safe_ruby_with_sinatra/Protocolfile.safe_ruby_with_sinatra +44 -0
  20. data/examples/safe_ruby_with_sinatra/app.rb +28 -0
  21. data/examples/safe_ruby_with_sinatra/post.rb +34 -0
  22. data/examples/safe_ruby_with_sinatra/views/index.erb +32 -0
  23. data/examples/unsafe_ruby/Gemfile +5 -0
  24. data/examples/unsafe_ruby/Protocolfile.unsafe_ruby +15 -0
  25. data/examples/unsafe_ruby/config_unsafe_ruby.ru +24 -0
  26. data/exe/toycol +6 -0
  27. data/lib/rack/handler/toycol.rb +65 -0
  28. data/lib/toycol.rb +20 -1
  29. data/lib/toycol/client.rb +38 -0
  30. data/lib/toycol/command.rb +132 -0
  31. data/lib/toycol/const.rb +102 -0
  32. data/lib/toycol/helper.rb +27 -0
  33. data/lib/toycol/protocol.rb +126 -0
  34. data/lib/toycol/proxy.rb +116 -0
  35. data/lib/toycol/server.rb +124 -0
  36. data/lib/toycol/version.rb +1 -1
  37. data/toycol.gemspec +3 -7
  38. metadata +48 -5
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 6e39fd4d4d223eef7eb8e86059fd061ebbb24259a1259b7f5b8bef228d6d9836
4
- data.tar.gz: 8d90ae7ed408d76a46da7726a280560d245e1372bca9d2a0857efe7bc22d6a3d
3
+ metadata.gz: 102026f42040d677807fb5fe1cd08797f564951096c15ac2c0150a757cc82926
4
+ data.tar.gz: d7b4312381d610821b197f688c871acbe26a6d70146c67441d23cbd52a0ed697
5
5
  SHA512:
6
- metadata.gz: 10d74fd171b7eec5618b1aeca4035a3f9bff05c12864285fb43fa83d1d53a97523276a19ac3a6185929e82854ce3701dd0f7d5963a55c38536cbe71828327809
7
- data.tar.gz: a73c3c5c7992ba1bebb34f8db9bfc8061a066a6c2b30ead33c8dfdc79a8b540092f540b793dd67c164dc277766dd7e6ce030b00b17d30148c28f5993fab4157e
6
+ metadata.gz: 11eb3611d926c804f1f0d632f40daf2a37b7f663bdb449c69c2353d608dba87161723f4380d5dedfa78a46f1d264dde625b9bdd30ba6dda6e64eed12964f83cf
7
+ data.tar.gz: 9c38815ef3861ad35ac635f713fb2f6b459ee6cbc64cbe9da56ec355381a5f21c30189e28ebe92f961406b99d9349631b52571729fd8c290d94cd61c0eefd4ea
@@ -0,0 +1,29 @@
1
+ ---
2
+ name: Bug report
3
+ about: Create a report to help us improve
4
+ title: "[BUG]"
5
+ labels: bug
6
+ assignees: ''
7
+
8
+ ---
9
+
10
+ ## Describe the bug
11
+ A clear and concise description of what the bug is.
12
+
13
+ ## To Reproduce
14
+ Steps to reproduce the behavior:
15
+ 1. Go to '...'
16
+ 2. Click on '....'
17
+ 3. Scroll down to '....'
18
+ 4. See error
19
+
20
+ ## Expected behavior
21
+ A clear and concise description of what you expected to happen.
22
+
23
+ ## Environment
24
+ - Ruby Version:
25
+ - Rack Version:
26
+ - Puma Version:
27
+
28
+ ## Additional context
29
+ Add any other context about the problem here.
@@ -0,0 +1,9 @@
1
+ version: 2
2
+ updates:
3
+ - package-ecosystem: bundler
4
+ directory: "/"
5
+ schedule:
6
+ interval: daily
7
+ time: "06:00"
8
+ open-pull-requests-limit: 10
9
+ rebase-strategy: "disabled"
@@ -5,12 +5,15 @@ on: [push,pull_request]
5
5
  jobs:
6
6
  build:
7
7
  runs-on: ubuntu-latest
8
+ strategy:
9
+ matrix:
10
+ ruby: [2.6, 2.7, 3.0, head]
8
11
  steps:
9
12
  - uses: actions/checkout@v2
10
13
  - name: Set up Ruby
11
14
  uses: ruby/setup-ruby@v1
12
15
  with:
13
- ruby-version: 3.0.0
16
+ ruby-version: ${{ matrix.ruby }}
14
17
  bundler-cache: true
15
18
  - name: Run the default task
16
19
  run: bundle exec rake
data/.gitignore CHANGED
@@ -7,4 +7,5 @@
7
7
  /spec/reports/
8
8
  /tmp/
9
9
 
10
+ .ruby-version
10
11
  Gemfile.lock
data/.rubocop.yml CHANGED
@@ -9,7 +9,14 @@ AllCops:
9
9
  - 'Rakefile'
10
10
  - 'toycol.gemspec'
11
11
  NewCops: enable
12
- TargetRubyVersion: 3.0
12
+ TargetRubyVersion: 2.6
13
+
14
+ Style/Documentation:
15
+ Enabled: false
16
+
17
+ Style/StringConcatenation:
18
+ Exclude:
19
+ - lib/toycol/server.rb
13
20
 
14
21
  Style/StringLiterals:
15
22
  Enabled: true
@@ -21,3 +28,21 @@ Style/StringLiteralsInInterpolation:
21
28
 
22
29
  Layout/LineLength:
23
30
  Max: 120
31
+
32
+ Layout/HashAlignment:
33
+ Exclude:
34
+ - lib/toycol/server.rb
35
+
36
+ Metrics:
37
+ Exclude:
38
+ - lib/toycol/proxy.rb
39
+ - lib/toycol/server.rb
40
+
41
+ Metrics/AbcSize:
42
+ Max: 30
43
+
44
+ Metrics/ClassLength:
45
+ Max: 400
46
+
47
+ Metrics/MethodLength:
48
+ Max: 15
data/CHANGELOG.md CHANGED
@@ -1,5 +1,5 @@
1
1
  ## [Unreleased]
2
2
 
3
- ## [0.1.0] - 2021-07-12
3
+ ## [0.0.1] - 2021-07-12
4
4
 
5
5
  - Initial release
data/README.md CHANGED
@@ -1,8 +1,6 @@
1
1
  # Toycol
2
2
 
3
- Welcome to your new gem! In this directory, you'll find the files you need to be able to package up your Ruby library into a gem. Put your Ruby code in the file `lib/toycol`. To experiment with that code, run `bin/console` for an interactive prompt.
4
-
5
- TODO: Delete this and the text above, and describe your gem
3
+ Toy Application Protocol framework
6
4
 
7
5
  ## Installation
8
6
 
@@ -22,7 +20,7 @@ Or install it yourself as:
22
20
 
23
21
  ## Usage
24
22
 
25
- TODO: Write usage instructions here
23
+ WIP
26
24
 
27
25
  ## Development
28
26
 
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ source "https://rubygems.org"
4
+
5
+ gem "toycol", path: "../../"
@@ -0,0 +1,23 @@
1
+ # frozen_string_literal: true
2
+
3
+ Toycol::Protocol.define(:duck) do
4
+ custom_status_codes(
5
+ 600 => "I'm afraid you are not a duck..."
6
+ )
7
+ additional_request_methods "OTHER"
8
+
9
+ request.path do |message|
10
+ %r{(?<path>/\w*)}.match(message)[:path]
11
+ end
12
+
13
+ request.query do |message|
14
+ /\?(?<query>.+)/.match(message) { |m| m[:query] }
15
+ end
16
+
17
+ request.http_method do |message|
18
+ case message.scan(/quack/).size
19
+ when 2 then "GET"
20
+ else "OTHER"
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,59 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "rack"
4
+ require "toycol"
5
+
6
+ Toycol::Protocol.use(:duck)
7
+
8
+ # Duck protocol application
9
+ class App
10
+ def call(env)
11
+ case env["REQUEST_METHOD"]
12
+ when "GET"
13
+ case env["PATH_INFO"]
14
+ when "/posts"
15
+ return app_for_get_with_query if env["QUERY_STRING"] == "user_id=1"
16
+
17
+ app_for_get
18
+ when "/" then app_for_get_to_root
19
+ end
20
+ when "OTHER" then app_for_other
21
+ end
22
+ end
23
+
24
+ private
25
+
26
+ def app_for_get_with_query
27
+ [
28
+ 200,
29
+ { "Content-Type" => "text/html" },
30
+ ["quack quack, I am the No.1 duck\n"]
31
+ ]
32
+ end
33
+
34
+ def app_for_get
35
+ [
36
+ 200,
37
+ { "Content-Type" => "text/html" },
38
+ ["quack quack, quack quack, quack, quack\n", "quack quack, I am the No.1 duck\n"]
39
+ ]
40
+ end
41
+
42
+ def app_for_get_to_root
43
+ [
44
+ 200,
45
+ { "Content-Type" => "text/html" },
46
+ ["Hello, This app is running on Sample duck protocol.\n"]
47
+ ]
48
+ end
49
+
50
+ def app_for_other
51
+ [
52
+ 600,
53
+ { "Content-Type" => "text/html" },
54
+ ["Sorry, this application is only for ducks...\n"]
55
+ ]
56
+ end
57
+ end
58
+
59
+ run App.new
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ source "https://rubygems.org"
4
+
5
+ gem "toycol", path: "../../"
@@ -0,0 +1,18 @@
1
+ Toycol::Protocol.define(:rubylike) do
2
+ custom_status_codes(
3
+ 700 => "Hmm...",
4
+ )
5
+
6
+ additional_request_methods "OTHER"
7
+
8
+ request.path do |message|
9
+ /['"](?<path>.+)['"]/.match(message)[:path]
10
+ end
11
+
12
+ request.http_method do |message|
13
+ case /\.(?<method>[A-z]+)/.match(message)&.captures&.first
14
+ when "get" then "GET"
15
+ else "OTHER"
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,27 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "rack"
4
+ require "toycol"
5
+
6
+ Toycol::Protocol.use(:rubylike)
7
+
8
+ class App
9
+ def call(env)
10
+ case env["REQUEST_METHOD"]
11
+ when "GET"
12
+ [
13
+ 200,
14
+ { "Content-Type" => "text/html" },
15
+ ["I love ruby!\n", "I love RubyKaigi!\n"]
16
+ ]
17
+ when "OTHER"
18
+ [
19
+ 700,
20
+ { "Content-Type" => "text/html" },
21
+ ["Sorry, but I'd like you to speak more like a Ruby programmer...\n"]
22
+ ]
23
+ end
24
+ end
25
+ end
26
+
27
+ run App.new
@@ -0,0 +1,6 @@
1
+ # frozen_string_literal: true
2
+
3
+ source "https://rubygems.org"
4
+
5
+ gem "puma"
6
+ gem "toycol", path: "../../"
@@ -0,0 +1,47 @@
1
+ module SafeRuby
2
+ PARSER_REGEX = /["'](?<path>\/.*)["']\.(?<method>[A-z]+)/
3
+ QUERY_REGEX = /query?.*\{(?<query>.*)\}/
4
+ INPUT_REGEX = /input?.*\{(?<input>.*)\}/
5
+ end
6
+
7
+ Toycol::Protocol.define(:safe_ruby) do |message|
8
+ using Module.new {
9
+ refine String do
10
+ # Ex. '/posts'.get
11
+ # Ex. (with query string) '/posts'.get(query: { user_id: 2 })
12
+ def get(options = {})
13
+ Toycol::Protocol.request.query { options[:query] } if options[:query]
14
+ Toycol::Protocol.request.http_method { "GET" }
15
+ end
16
+
17
+ # Ex. '/posts'.post(input: { user_id: 1, body: 'This is a post request' })
18
+ def post(options = {})
19
+ Toycol::Protocol.request.input { options[:input] } if options[:input]
20
+ Toycol::Protocol.request.http_method { "POST" }
21
+ end
22
+
23
+ def parse_as_queries
24
+ split(",").map { |str| str.scan(/\w+/).join("=") }
25
+ end
26
+
27
+ def parse_as_inputs
28
+ split(",").map { |str| str.split(":").map { |s| s.strip! && s.gsub(/['"]/, "") }.join("=") }
29
+ end
30
+ end
31
+ }
32
+
33
+ path, method = SafeRuby::PARSER_REGEX.match(message) { |m| [m[:path], m[:method]] }
34
+ query = SafeRuby::QUERY_REGEX.match(message) { |m| m[:query].parse_as_queries }&.join("&")
35
+ input = SafeRuby::INPUT_REGEX.match(message) { |m| m[:input].parse_as_inputs }&.join("&")
36
+ args = {}
37
+
38
+ request.path { path }
39
+
40
+ %i[query input].each do |k|
41
+ if v = binding.local_variable_get(k)
42
+ args[*k] = v
43
+ end
44
+ end
45
+
46
+ request_path.public_send(method, args)
47
+ end
@@ -0,0 +1,55 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "rack"
4
+ require "toycol"
5
+
6
+ Toycol::Protocol.use(:safe_ruby)
7
+
8
+ class App
9
+ def call(env)
10
+ case env["REQUEST_METHOD"]
11
+ when "GET"
12
+ case env["PATH_INFO"]
13
+ when "/posts"
14
+ return app_for_get_with_query if env["QUERY_STRING"] == "user_id=2"
15
+
16
+ app_for_get
17
+ end
18
+ when "POST"
19
+ input = env["rack.input"].gets
20
+ created = input.split("&").map { |str| str.split("=") }.to_h
21
+
22
+ app_for_post(user_id: created["user_id"], body: created["body"])
23
+ end
24
+ end
25
+
26
+ private
27
+
28
+ def app_for_get_with_query
29
+ [
30
+ 200,
31
+ { "Content-Type" => "text/html" },
32
+ ["User<2> I love RubyKaigi!\n"]
33
+ ]
34
+ end
35
+
36
+ def app_for_get
37
+ [
38
+ 200,
39
+ { "Content-Type" => "text/html" },
40
+ ["User<1> I love Ruby!\n", "User<2> I love RubyKaigi!\n"]
41
+ ]
42
+ end
43
+
44
+ def app_for_post(user_id:, body:)
45
+ [
46
+ 201,
47
+ { "Content-Type" => "text/html", "Location" => "/posts" },
48
+ ["User<1> I love Ruby!\n",
49
+ "User<2> I love RubyKaigi!\n",
50
+ "User<#{user_id}> #{body}\n"]
51
+ ]
52
+ end
53
+ end
54
+
55
+ run App.new
@@ -0,0 +1,10 @@
1
+ # frozen_string_literal: true
2
+
3
+ source "https://rubygems.org"
4
+
5
+ # git_source(:github) {|repo_name| "https://github.com/#{repo_name}" }
6
+
7
+ gem "puma"
8
+ gem "sinatra"
9
+ gem "sinatra-contrib"
10
+ gem "toycol", path: "../../"
@@ -0,0 +1,44 @@
1
+ module SafeRubyWithSinatra
2
+ PARSER_REGEX = /["'](?<path>\/.*)["']\.(?<method>[A-z]+)/
3
+ QUERY_REGEX = /query?.*\{(?<query>.*)\}/
4
+ INPUT_REGEX = /input?.*\{(?<input>.*)\}/
5
+ end
6
+
7
+ Toycol::Protocol.define(:safe_ruby_with_sinatra) do |message|
8
+ using Module.new {
9
+ refine String do
10
+ def get(options = {})
11
+ Toycol::Protocol.request.query { options[:query] } if options[:query]
12
+ Toycol::Protocol.request.http_method { "GET" }
13
+ end
14
+
15
+ def post(options = {})
16
+ Toycol::Protocol.request.input { options[:input] } if options[:input]
17
+ Toycol::Protocol.request.http_method { "POST" }
18
+ end
19
+
20
+ def parse_as_queries
21
+ split(",").map { |str| str.scan(/\w+/).join("=") }
22
+ end
23
+
24
+ def parse_as_inputs
25
+ split(",").map { |str| str.split(":").map { |s| s.strip! && s.gsub(/['"]/, "") }.join("=") }
26
+ end
27
+ end
28
+ }
29
+
30
+ path, method = SafeRubyWithSinatra::PARSER_REGEX.match(message) { |m| [m[:path], m[:method]] }
31
+ query = SafeRubyWithSinatra::QUERY_REGEX.match(message) { |m| m[:query].parse_as_queries }&.join("&")
32
+ input = SafeRubyWithSinatra::INPUT_REGEX.match(message) { |m| m[:input].parse_as_inputs }&.join("&")
33
+ args = {}
34
+
35
+ request.path { path }
36
+
37
+ %i[query input].each do |k|
38
+ if v = binding.local_variable_get(k)
39
+ args[*k] = v
40
+ end
41
+ end
42
+
43
+ request_path.public_send(method, args)
44
+ end