gen_server 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 9e256c6d2994f782837aea8435a41ba8f5d4322ac62ed4f9f9cf4ec1cdb1fa5a
4
+ data.tar.gz: 53342fd0596658d3a616298813368423efae86aaaf3069cc68b2c855e61c84d4
5
+ SHA512:
6
+ metadata.gz: 1674611e97fa539f90b02dfd77f3f7c367c654fb54d586371ee2ff5b8f40edce90ed9e97a9e2ae787cdd5da51f491d36d17eb6a9fde61bd99ced341fc6532eb7
7
+ data.tar.gz: dce0274547ef0dab17c71e16a7bab93708b6de2bcb7b25544a79b033cae2af4db3dd2c00f625f9857017d7234e51f6dfe8df222b69c7198e1d69addd5f71c16a
data/.rubocop.yml ADDED
@@ -0,0 +1,24 @@
1
+ require:
2
+ - rubocop-minitest
3
+ - rubocop-rake
4
+
5
+ AllCops:
6
+ TargetRubyVersion: 3.1
7
+ NewCops: enable
8
+
9
+ Metrics/MethodLength:
10
+ Enabled: false
11
+
12
+ Style/Documentation:
13
+ Enabled: false
14
+
15
+ Style/StringLiterals:
16
+ Enabled: true
17
+ EnforcedStyle: single_quotes
18
+
19
+ Style/StringLiteralsInInterpolation:
20
+ Enabled: true
21
+ EnforcedStyle: single_quotes
22
+
23
+ Layout/LineLength:
24
+ Max: 120
data/Gemfile ADDED
@@ -0,0 +1,12 @@
1
+ # frozen_string_literal: true
2
+
3
+ source 'https://rubygems.org'
4
+
5
+ gemspec
6
+
7
+ gem 'minitest', '~> 5.0'
8
+ gem 'minitest-proveit'
9
+ gem 'rake', '~> 13.0'
10
+ gem 'rubocop', '~> 1.21'
11
+ gem 'rubocop-minitest', require: false
12
+ gem 'rubocop-rake', require: false
data/Gemfile.lock ADDED
@@ -0,0 +1,51 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ gen_server (0.0.1)
5
+
6
+ GEM
7
+ remote: https://rubygems.org/
8
+ specs:
9
+ ast (2.4.2)
10
+ minitest (5.16.1)
11
+ minitest-proveit (1.0.0)
12
+ minitest (> 5, < 7)
13
+ parallel (1.22.1)
14
+ parser (3.1.2.0)
15
+ ast (~> 2.4.1)
16
+ rainbow (3.1.1)
17
+ rake (13.0.6)
18
+ regexp_parser (2.5.0)
19
+ rexml (3.2.5)
20
+ rubocop (1.30.1)
21
+ parallel (~> 1.10)
22
+ parser (>= 3.1.0.0)
23
+ rainbow (>= 2.2.2, < 4.0)
24
+ regexp_parser (>= 1.8, < 3.0)
25
+ rexml (>= 3.2.5, < 4.0)
26
+ rubocop-ast (>= 1.18.0, < 2.0)
27
+ ruby-progressbar (~> 1.7)
28
+ unicode-display_width (>= 1.4.0, < 3.0)
29
+ rubocop-ast (1.18.0)
30
+ parser (>= 3.1.1.0)
31
+ rubocop-minitest (0.20.1)
32
+ rubocop (>= 0.90, < 2.0)
33
+ rubocop-rake (0.6.0)
34
+ rubocop (~> 1.0)
35
+ ruby-progressbar (1.11.0)
36
+ unicode-display_width (2.1.0)
37
+
38
+ PLATFORMS
39
+ x86_64-linux
40
+
41
+ DEPENDENCIES
42
+ gen_server!
43
+ minitest (~> 5.0)
44
+ minitest-proveit
45
+ rake (~> 13.0)
46
+ rubocop (~> 1.21)
47
+ rubocop-minitest
48
+ rubocop-rake
49
+
50
+ BUNDLED WITH
51
+ 2.4.0.dev
data/LICENSE.txt ADDED
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2022 Shannon Skipper
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in
13
+ all copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
+ THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,19 @@
1
+ # GenServer
2
+
3
+ This is a Ruby implementation of GenServer using Ractors.
4
+
5
+ ## Installation
6
+
7
+ Add it to your bundle.
8
+ ```sh
9
+ bundle add gen_server
10
+ ```
11
+
12
+ Or just install it directly.
13
+ ```sh
14
+ gem install gen_server
15
+ ```
16
+
17
+ ## Usage
18
+
19
+ Check out the `example/` directory for now.
data/Rakefile ADDED
@@ -0,0 +1,15 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'bundler/gem_tasks'
4
+ require 'rake/testtask'
5
+ require 'rubocop/rake_task'
6
+
7
+ Rake::TestTask.new :test do |task|
8
+ task.libs << 'test'
9
+ task.libs << 'lib'
10
+ task.test_files = FileList['test/**/test_*.rb']
11
+ end
12
+
13
+ RuboCop::RakeTask.new
14
+
15
+ task default: %i[test rubocop]
data/Steepfile ADDED
@@ -0,0 +1,9 @@
1
+ # frozen_string_literal: true
2
+
3
+ target :lib do
4
+ signature 'sig'
5
+
6
+ check 'lib'
7
+
8
+ library 'securerandom', 'singleton'
9
+ end
@@ -0,0 +1,29 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative '../lib/gen_server'
4
+
5
+ class BasicStack
6
+ include GenServer
7
+
8
+ def init(stack)
9
+ [:ok, stack]
10
+ end
11
+
12
+ def handle_call(message, _from, (head, *tail))
13
+ message => :pop
14
+
15
+ [:reply, head, tail]
16
+ end
17
+
18
+ def handle_cast((cast, element), state)
19
+ cast => :push
20
+ state.unshift(element)
21
+
22
+ [:noreply, element]
23
+ end
24
+ end
25
+
26
+ GenServer.start_link(BasicStack, [:hello]) => [:ok, pid]
27
+ p GenServer.call(pid, :pop)
28
+ p GenServer.cast(pid, %i[push world])
29
+ p GenServer.call(pid, :pop)
data/example/noop.rb ADDED
@@ -0,0 +1,12 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative '../lib/gen_server'
4
+
5
+ class Noop
6
+ include GenServer
7
+ end
8
+
9
+ GenServer.start_link(Noop, []) => [:ok, pid]
10
+ p GenServer.call(pid, :foo)
11
+ p GenServer.cast(pid, %i[push bar])
12
+ p GenServer.call(pid, :foo)
data/example/stack.rb ADDED
@@ -0,0 +1,47 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative '../lib/gen_server'
4
+
5
+ class Stack
6
+ include GenServer
7
+
8
+ ##
9
+ # Client
10
+ class << self
11
+ def start_link(default = [])
12
+ GenServer.start_link(self, default)
13
+ end
14
+
15
+ def push(pid, element)
16
+ GenServer.cast(pid, [:push, element])
17
+ end
18
+
19
+ def pop(pid)
20
+ GenServer.call(pid, :pop)
21
+ end
22
+ end
23
+
24
+ ##
25
+ # Server (callbacks)
26
+ def init(stack)
27
+ [:ok, stack]
28
+ end
29
+
30
+ def handle_call(message, _from, (head, *tail))
31
+ message => :pop
32
+
33
+ [:reply, head, tail]
34
+ end
35
+
36
+ def handle_cast((cast, element), state)
37
+ cast => :push
38
+ state.unshift(element)
39
+
40
+ [:noreply, element]
41
+ end
42
+ end
43
+
44
+ Stack.start_link([:hello]) => [:ok, pid]
45
+ p Stack.pop(pid)
46
+ p Stack.push(pid, :world)
47
+ p Stack.pop(pid)
@@ -0,0 +1,7 @@
1
+ # frozen_string_literal: true
2
+
3
+ module GenServer
4
+ class Registry
5
+ Info = Struct.new(:actor, :klass)
6
+ end
7
+ end
@@ -0,0 +1,29 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'registry/info'
4
+
5
+ module GenServer
6
+ class Registry
7
+ include Singleton
8
+
9
+ attr_reader :pids
10
+
11
+ def initialize
12
+ @pids = {}
13
+ end
14
+
15
+ class << self
16
+ def []=(pid, info)
17
+ instance.pids[pid] = info
18
+ end
19
+
20
+ def actor(pid)
21
+ instance.pids.fetch(pid).actor
22
+ end
23
+
24
+ def klass(pid)
25
+ instance.pids.fetch(pid).klass
26
+ end
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ module GenServer
4
+ VERSION = '0.0.1'
5
+ end
data/lib/gen_server.rb ADDED
@@ -0,0 +1,55 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'securerandom'
4
+ require 'singleton'
5
+ require_relative 'gen_server/registry'
6
+ require_relative 'gen_server/version'
7
+
8
+ module GenServer
9
+ def initialize(...)
10
+ init(...)
11
+ end
12
+
13
+ def init(...) = nil
14
+ def handle_call(...) = [:reply, nil, nil]
15
+ def handle_cast(...) = [:noreply, nil]
16
+
17
+ class << self
18
+ def start_link(klass, state = [])
19
+ pid = SecureRandom.uuid
20
+
21
+ actor = Ractor.new(state, name: pid) do |state|
22
+ GenServer.receive(state)
23
+ end
24
+
25
+ Registry[pid] = Registry::Info.new(actor:, klass:)
26
+
27
+ [:ok, pid]
28
+ end
29
+
30
+ def receive(state)
31
+ case Ractor.receive
32
+ in [:cast, message, klass]
33
+ klass.allocate.handle_cast(message, state) => [:noreply, new_state]
34
+ receive(new_state)
35
+ in [:call, sender, message, klass]
36
+ klass.allocate.handle_call(message, sender, state) => [:reply, reply, new_state]
37
+ sender.send [:ok, reply]
38
+ receive(new_state)
39
+ end
40
+ end
41
+
42
+ def cast(pid, message)
43
+ Registry.actor(pid).send [:cast, message, Registry.klass(pid)]
44
+
45
+ :ok
46
+ end
47
+
48
+ def call(pid, message)
49
+ Registry.actor(pid).send [:call, Ractor.current, message, Registry.klass(pid)]
50
+ Ractor.receive => [:ok, response]
51
+
52
+ response
53
+ end
54
+ end
55
+ end
@@ -0,0 +1,27 @@
1
+ module GenServer
2
+ VERSION: String
3
+
4
+ def initialize: (*untyped noname) -> void
5
+ def init: (*untyped noname) -> untyped
6
+ def handle_call: (*untyped noname) -> [:reply, untyped, untyped]
7
+ def handle_cast: (*untyped noname) -> [:noreply, untyped]
8
+ def self.start_link: (singleton(Class) klass, ?Array[untyped] state) -> bot
9
+ def self.receive: (untyped state) -> bot
10
+ def self.cast: (String pid, [:push, untyped] message) -> :ok
11
+ def self.call: (String pid, :pop message) -> untyped
12
+
13
+ class Registry
14
+ include Singleton
15
+
16
+ attr_reader pids: Hash[String, Struct[untyped]]
17
+ def initialize: -> void
18
+ def self.[]=: (String pid, Struct[untyped] info) -> untyped
19
+ def self.actor: (String pid) -> Ractor
20
+ def self.klass: (String pid) -> Class
21
+
22
+ class Info < Struct[untyped]
23
+ attr_accessor actor(): Ractor
24
+ attr_accessor klass(): Class
25
+ end
26
+ end
27
+ end
metadata ADDED
@@ -0,0 +1,59 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: gen_server
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - Shannon Skipper
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2022-06-22 00:00:00.000000000 Z
12
+ dependencies: []
13
+ description: A GenServer implemented with Ruby Ractors
14
+ email:
15
+ - shannonskipper@gmail.com
16
+ executables: []
17
+ extensions: []
18
+ extra_rdoc_files: []
19
+ files:
20
+ - ".rubocop.yml"
21
+ - Gemfile
22
+ - Gemfile.lock
23
+ - LICENSE.txt
24
+ - README.md
25
+ - Rakefile
26
+ - Steepfile
27
+ - example/basic_stack.rb
28
+ - example/noop.rb
29
+ - example/stack.rb
30
+ - lib/gen_server.rb
31
+ - lib/gen_server/registry.rb
32
+ - lib/gen_server/registry/info.rb
33
+ - lib/gen_server/version.rb
34
+ - sig/gen_server.rbs
35
+ homepage: https://github.com/havenwood/gen_server
36
+ licenses:
37
+ - MIT
38
+ metadata:
39
+ rubygems_mfa_required: 'true'
40
+ post_install_message:
41
+ rdoc_options: []
42
+ require_paths:
43
+ - lib
44
+ required_ruby_version: !ruby/object:Gem::Requirement
45
+ requirements:
46
+ - - ">="
47
+ - !ruby/object:Gem::Version
48
+ version: 3.1.0
49
+ required_rubygems_version: !ruby/object:Gem::Requirement
50
+ requirements:
51
+ - - ">="
52
+ - !ruby/object:Gem::Version
53
+ version: '0'
54
+ requirements: []
55
+ rubygems_version: 3.4.0.dev
56
+ signing_key:
57
+ specification_version: 4
58
+ summary: A Ractor-backed GenServer
59
+ test_files: []