murasaki 0.0.1 → 0.1.0

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
  SHA1:
3
- metadata.gz: 0acb7462bef6b0277cbfdfbb84ba90f3394158df
4
- data.tar.gz: 1ea68e3f5bc60ac1af1df69f7c1c250414a67f21
3
+ metadata.gz: 9ecdeb71724f0d1efe13027d3acee86a7575b1f4
4
+ data.tar.gz: 4523b9a2b5ebb11f93002b3190d360bc8ac667e3
5
5
  SHA512:
6
- metadata.gz: dfb808c62ad84b2ebde6088251a95d092800c0937b7fa8d9022dcbc0e98af00ce5491befc66f99fdfda3cb1f0b25b9cfd2a9c8f73fd8267699c9479e46fc71e1
7
- data.tar.gz: f1070c1e11587753a49c0bfc54ba2d91f4078dd716fa31080c65d3d3b539953c708ff14f981cc1857a256f51777dc6fe2ce0d04f99a088b7a06c3fa468b569ce
6
+ metadata.gz: ed8ca771ea23774b154477690d892ae658861fe929c42511357249468a562a5a598f005ae90f0b6798dc88d292ee6c948e815c2d52a0154b74cb05079bead52a
7
+ data.tar.gz: 81e4529da54237d5fe8dbe536c86eaca74c99055c60f781fe9aac6247728babeed2ac8ce19dedca4653db62390e59d7ecd88340b5cde2adf3dd4ee4bdb4d20e4
@@ -0,0 +1,9 @@
1
+ root = true
2
+
3
+ [*]
4
+ end_of_line = lf
5
+ insert_final_newline = true
6
+
7
+ [*.rb]
8
+ indent_style = space
9
+ indent_size = 2
@@ -0,0 +1,7 @@
1
+ require 'fiber'
2
+ require 'nio'
3
+
4
+ require_relative 'murasaki/version'
5
+ require_relative 'murasaki/event_loop'
6
+ require_relative 'murasaki/timer'
7
+ require_relative 'murasaki/promise'
@@ -0,0 +1,118 @@
1
+ ##
2
+ # EventLoop Module, providing main loop for events
3
+ module EventLoop
4
+ class << self
5
+ # Config EvnetLoop, call by default if any other methods called
6
+ # @param [NIO::Selector] selector an event selector
7
+ def config(selector = NIO::Selector.new)
8
+ # Raw NIO Selector
9
+ @selector = selector
10
+ # Array of active timers
11
+ @timers = []
12
+ # Hash of io and its callback
13
+ @ios = Hash.new
14
+ # IO queue
15
+ @queue = Hash.new
16
+ end
17
+
18
+ # Add timer in event loop
19
+ # @param [EventLoop::Timer] timer timer to insert
20
+ # @return [nil] nil
21
+ def add_timer(timer)
22
+ config if @selector.nil?
23
+ timer.start_time = Time.now.to_f + timer.time
24
+ @timers << timer
25
+ nil
26
+ end
27
+
28
+ # Register I/O event with queue protection
29
+ # @param [IO] io io to register
30
+ # @param [Symbol] interest :r for read only, :w for write only, and :rw for both
31
+ # @yield what to run when io callbacks
32
+ # @return [nil] nil
33
+ def register(io, interest=(:rw), &callback)
34
+ config if @selector.nil?
35
+ if @queue[io.to_i].nil?
36
+ @queue[io.to_i] = Array.new
37
+ register_raw(io, interest, callback)
38
+ else
39
+ @queue[io.to_i] << [io, interest, callback]
40
+ end
41
+ nil
42
+ end
43
+
44
+ # Register I/O event directly, without any queue protection
45
+ # @param [IO] io io to register
46
+ # @param [Symbol] interest :r for read only, :w for write only, and :rw for both
47
+ # @param [Proc] callback what to run when io callbacks
48
+ # @return [nil] nil
49
+ def register_raw(io, interest=(:rw), callback)
50
+ config if @selector.nil?
51
+ @selector.register(io, interest)
52
+ @ios[io] = { callback: callback }
53
+ nil
54
+ end
55
+
56
+ # Deregister I/O event
57
+ # @param [IO] io io to deregister
58
+ # @return [nil] nil
59
+ def deregister(io)
60
+ fd = io.to_i
61
+ @selector.deregister(io)
62
+ @ios.delete(io)
63
+ next_register = @queue[fd].shift
64
+ next_register.nil? ? @queue.delete(fd) : register_raw(*next_register)
65
+ nil
66
+ end
67
+
68
+ # Run I/O selector once
69
+ # @return [nil] nil
70
+ def run_once
71
+ config if @selector.nil?
72
+ @selector.select(0.2) do |monitor| # Timeout for 0.2 secs
73
+ @ios[monitor.io][:callback].call(monitor)
74
+ end
75
+ timer_once
76
+ nil
77
+ end
78
+
79
+ # Run timer once
80
+ # @return [nil] nil
81
+ def timer_once
82
+ config if @selector.nil?
83
+ now_time = Time.now.to_f
84
+ @timers.delete_if do |timer|
85
+ if timer.start_time < now_time
86
+ timer.callback.call
87
+ true
88
+ end
89
+ end
90
+ nil
91
+ end
92
+
93
+ # Start the event loop
94
+ # @return [nil] nil
95
+ def start
96
+ return if running?
97
+ @stop = false
98
+ until @stop
99
+ run_once
100
+ end
101
+ @stop = nil
102
+ end
103
+
104
+ # Set the stop flag
105
+ # @return [nil] nil
106
+ def stop
107
+ @stop = true
108
+ nil
109
+ end
110
+
111
+ # Detect the stop flag
112
+ # @return [Boolean] return if eventloop is set to be stopped
113
+ def running?
114
+ @stop = true if @stop.nil?
115
+ !@stop
116
+ end
117
+ end
118
+ end
@@ -0,0 +1,70 @@
1
+ ##
2
+ # Meta-programming String for Syntactic Sugars
3
+ # Referenced from {Qiita}[http://qiita.com/south37/items/99a60345b22ef395d424]
4
+ class Promise
5
+ # Init a Promise
6
+ # @param [Proc] callback an async method
7
+ def initialize(&callback)
8
+ @callback = callback
9
+ end
10
+
11
+ # Define what to do after a method callbacks
12
+ # @param [Proc] resolve what on callback
13
+ # @return [nil] nil
14
+ def then(&resolve)
15
+ @callback.call(resolve)
16
+ end
17
+ end
18
+
19
+ module Kernel
20
+ # Make fiber as async chain
21
+ # @param [Fiber] fiber root of async chain
22
+ def async_fiber(fiber)
23
+ chain = proc do |result|
24
+ next unless result.is_a? Promise
25
+ result.then do |val|
26
+ chain.call(fiber.resume(val))
27
+ end
28
+ end
29
+ chain.call(fiber.resume)
30
+ end
31
+
32
+ # Define an async method
33
+ # @param [Symbol] method method name
34
+ # @yield async method
35
+ # @example
36
+ # async :hello do
37
+ # puts 'Hello'
38
+ # end
39
+ def async(method)
40
+ define_singleton_method method do |*args|
41
+ async_fiber(Fiber.new {yield(*args)})
42
+ end
43
+ end
44
+
45
+ # Block the I/O to wait for async method response
46
+ # @param [Promise] promise promise method
47
+ # @example
48
+ # result = await SQL.query('SELECT * FROM hello')
49
+ def await(promise)
50
+ result = Fiber.yield promise
51
+ if result.is_a? PromiseException
52
+ raise result.payload
53
+ end
54
+ result
55
+ end
56
+ end
57
+
58
+
59
+ ##
60
+ # Exceptions for Promises
61
+ # @!attribute [r] payload
62
+ # @return [Exception] raw execption
63
+ class PromiseException < Exception
64
+ attr_reader :payload
65
+ # Init PromiseException with existed Exception
66
+ # @param [Exception] payload raw execption
67
+ def initialize(payload)
68
+ @payload = payload
69
+ end
70
+ end
@@ -0,0 +1,22 @@
1
+ ##
2
+ # Timer Object in EventLoop
3
+ # @!attribute [r] time
4
+ # @return [Float] timeout length
5
+ # @!attribute [r] callback
6
+ # @return [Proc] proc to call when callbacks
7
+ # @!attribute start_time
8
+ # @return [Float] when timer should callbacks
9
+ class EventLoop::Timer
10
+
11
+ attr_reader :time, :callback
12
+ attr_accessor :start_time
13
+
14
+ # Init a timer with a time period and callback
15
+ # @param [Float] time timeout length
16
+ # @yield proc to call when callbacks
17
+ def initialize(time, &callback)
18
+ @time = time
19
+ @callback = callback
20
+ @start_time = Float::INFINITY
21
+ end
22
+ end
@@ -0,0 +1,5 @@
1
+ # Murasaki Module
2
+ module Murasaki
3
+ # Current Version Code
4
+ VERSION = '0.1.0'.freeze
5
+ end
@@ -0,0 +1,19 @@
1
+ require './lib/murasaki/version'
2
+
3
+ Gem::Specification.new do |s|
4
+ s.name = 'murasaki'
5
+ s.version = Murasaki::VERSION
6
+ s.required_ruby_version = '>=2.2.6'
7
+ s.date = Time.now.strftime('%Y-%m-%d')
8
+ s.summary = 'Event Kernel for Ruby'
9
+ s.description = 'Event Kernel for Ruby, power for midori project'
10
+ s.authors = ['HeckPsi Lab']
11
+ s.email = 'business@heckpsi.com'
12
+ s.require_paths = ['lib']
13
+ s.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(spec|.resources)/}) } \
14
+ - %w(README.md CONTRIBUTOR_COVENANT_CODE_OF_CONDUCT.md Gemfile Rakefile em-midori.gemspec .gitignore .rspec .codeclimate.yml .rubocop.yml .travis.yml logo.png Rakefile Gemfile)
15
+ s.homepage = 'https://github.com/heckpsi-lab/murasaki'
16
+ s.metadata = { 'issue_tracker' => 'https://github.com/heckpsi-lab/murasaki/issues' }
17
+ s.license = 'MIT'
18
+ s.add_runtime_dependency 'nio4r', '~> 2.0'
19
+ end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: murasaki
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.1
4
+ version: 0.1.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - HeckPsi Lab
@@ -9,14 +9,35 @@ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
11
  date: 2017-06-13 00:00:00.000000000 Z
12
- dependencies: []
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: nio4r
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '2.0'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '2.0'
13
27
  description: Event Kernel for Ruby, power for midori project
14
28
  email: business@heckpsi.com
15
29
  executables: []
16
30
  extensions: []
17
31
  extra_rdoc_files: []
18
32
  files:
33
+ - ".editorconfig"
19
34
  - LICENSE
35
+ - lib/murasaki.rb
36
+ - lib/murasaki/event_loop.rb
37
+ - lib/murasaki/promise.rb
38
+ - lib/murasaki/timer.rb
39
+ - lib/murasaki/version.rb
40
+ - murasaki.gemspec
20
41
  homepage: https://github.com/heckpsi-lab/murasaki
21
42
  licenses:
22
43
  - MIT