iruby 0.2.7 → 0.5.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (69) hide show
  1. checksums.yaml +5 -5
  2. data/.github/workflows/ubuntu.yml +62 -0
  3. data/CHANGES +62 -0
  4. data/Gemfile +3 -1
  5. data/LICENSE +1 -1
  6. data/README.md +148 -27
  7. data/Rakefile +36 -10
  8. data/ci/Dockerfile.base.erb +41 -0
  9. data/ci/Dockerfile.main.erb +7 -0
  10. data/ci/requirements.txt +1 -0
  11. data/docker/setup.sh +15 -0
  12. data/docker/test.sh +7 -0
  13. data/iruby.gemspec +14 -18
  14. data/lib/iruby.rb +19 -3
  15. data/lib/iruby/backend.rb +22 -2
  16. data/lib/iruby/command.rb +76 -13
  17. data/lib/iruby/display.rb +69 -39
  18. data/lib/iruby/formatter.rb +5 -4
  19. data/lib/iruby/input.rb +41 -0
  20. data/lib/iruby/input/README.ipynb +502 -0
  21. data/lib/iruby/input/README.md +299 -0
  22. data/lib/iruby/input/autoload.rb +25 -0
  23. data/lib/iruby/input/builder.rb +67 -0
  24. data/lib/iruby/input/button.rb +47 -0
  25. data/lib/iruby/input/cancel.rb +32 -0
  26. data/lib/iruby/input/checkbox.rb +74 -0
  27. data/lib/iruby/input/date.rb +37 -0
  28. data/lib/iruby/input/field.rb +31 -0
  29. data/lib/iruby/input/file.rb +57 -0
  30. data/lib/iruby/input/form.rb +77 -0
  31. data/lib/iruby/input/label.rb +27 -0
  32. data/lib/iruby/input/multiple.rb +76 -0
  33. data/lib/iruby/input/popup.rb +41 -0
  34. data/lib/iruby/input/radio.rb +59 -0
  35. data/lib/iruby/input/select.rb +59 -0
  36. data/lib/iruby/input/textarea.rb +23 -0
  37. data/lib/iruby/input/widget.rb +34 -0
  38. data/lib/iruby/jupyter.rb +77 -0
  39. data/lib/iruby/kernel.rb +67 -22
  40. data/lib/iruby/ostream.rb +24 -8
  41. data/lib/iruby/session.rb +85 -67
  42. data/lib/iruby/session/cztop.rb +70 -0
  43. data/lib/iruby/session/ffi_rzmq.rb +87 -0
  44. data/lib/iruby/session/mixin.rb +47 -0
  45. data/lib/iruby/session_adapter.rb +66 -0
  46. data/lib/iruby/session_adapter/cztop_adapter.rb +45 -0
  47. data/lib/iruby/session_adapter/ffirzmq_adapter.rb +55 -0
  48. data/lib/iruby/session_adapter/pyzmq_adapter.rb +77 -0
  49. data/lib/iruby/utils.rb +5 -2
  50. data/lib/iruby/version.rb +1 -1
  51. data/run-test.sh +12 -0
  52. data/tasks/ci.rake +65 -0
  53. data/test/helper.rb +90 -0
  54. data/test/integration_test.rb +22 -11
  55. data/test/iruby/backend_test.rb +37 -0
  56. data/test/iruby/command_test.rb +207 -0
  57. data/test/iruby/jupyter_test.rb +27 -0
  58. data/test/iruby/mime_test.rb +32 -0
  59. data/test/iruby/multi_logger_test.rb +1 -2
  60. data/test/iruby/session_adapter/cztop_adapter_test.rb +20 -0
  61. data/test/iruby/session_adapter/ffirzmq_adapter_test.rb +20 -0
  62. data/test/iruby/session_adapter/session_adapter_test_base.rb +27 -0
  63. data/test/iruby/session_adapter_test.rb +91 -0
  64. data/test/iruby/session_test.rb +47 -0
  65. data/test/run-test.rb +18 -0
  66. metadata +130 -46
  67. data/.travis.yml +0 -16
  68. data/CONTRIBUTORS +0 -19
  69. data/test/test_helper.rb +0 -5
@@ -0,0 +1,59 @@
1
+ module IRuby
2
+ module Input
3
+ class Select < Label
4
+ needs :options, :default
5
+
6
+ builder :select do |*args, **params|
7
+ key = :select
8
+ key, *args = args if args.first.is_a? Symbol
9
+
10
+ params[:key] = unique_key(key)
11
+ params[:options] = args
12
+ params[:default] ||= false
13
+
14
+ unless params[:options].include? params[:default]
15
+ params[:options] = [nil, *params[:options].compact]
16
+ end
17
+
18
+ add_field Select.new(**params)
19
+ end
20
+
21
+ def widget_css
22
+ <<-CSS
23
+ .iruby-select {
24
+ min-width: 25%;
25
+ margin-left: 0 !important;
26
+ }
27
+ CSS
28
+ end
29
+
30
+ def widget_js
31
+ <<-JS
32
+ $('.iruby-select').change(function(){
33
+ $(this).data('iruby-value',
34
+ $(this).find('option:selected').text()
35
+ );
36
+ });
37
+ JS
38
+ end
39
+
40
+ def widget_html
41
+ widget_label do
42
+ div class: 'form-control' do
43
+ params = {
44
+ class: 'iruby-select',
45
+ :'data-iruby-key' => @key,
46
+ :'data-iruby-value' => @default
47
+ }
48
+
49
+ select **params do
50
+ @options.each do |o|
51
+ option o, selected: @default == o
52
+ end
53
+ end
54
+ end
55
+ end
56
+ end
57
+ end
58
+ end
59
+ end
@@ -0,0 +1,23 @@
1
+ module IRuby
2
+ module Input
3
+ class Textarea < Field
4
+ needs rows: 5
5
+
6
+ builder :textarea do |key='textarea', **params|
7
+ params[:key] = unique_key key
8
+ add_field Textarea.new(**params)
9
+ end
10
+
11
+ def widget_html
12
+ widget_label do
13
+ textarea(
14
+ @default,
15
+ rows: @rows,
16
+ :'data-iruby-key' => @key,
17
+ class: 'form-control iruby-field'
18
+ )
19
+ end
20
+ end
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,34 @@
1
+ module IRuby
2
+ module Input
3
+ class Widget < Erector::Widget
4
+ needs key: nil
5
+
6
+ def widget_js; end
7
+ def widget_css; end
8
+ def widget_html; end
9
+ def content; widget_html; end
10
+
11
+ def self.builder method, &block
12
+ Builder.instance_eval do
13
+ define_method method, &block
14
+ end
15
+ end
16
+
17
+ def widget_join method, *args
18
+ strings = args.map do |arg|
19
+ arg.is_a?(String) ? arg : arg.send(method)
20
+ end
21
+ strings.uniq.join("\n")
22
+ end
23
+
24
+ def widget_display
25
+ IRuby.display(IRuby.html(
26
+ Erector.inline{ style raw(widget_css) }.to_html
27
+ ))
28
+
29
+ IRuby.display(IRuby.html(to_html))
30
+ IRuby.display(IRuby.javascript(widget_js))
31
+ end
32
+ end
33
+ end
34
+ end
@@ -0,0 +1,77 @@
1
+ module IRuby
2
+ module Jupyter
3
+ class << self
4
+ # User's default kernelspec directory is described here:
5
+ # https://jupyter.readthedocs.io/en/latest/projects/jupyter-directories.html
6
+ def default_data_dir
7
+ case
8
+ when windows?
9
+ appdata = windows_user_appdata
10
+ if !appdata.empty?
11
+ File.join(appdata, 'jupyter')
12
+ else
13
+ jupyter_config_dir = ENV.fetch('JUPYTER_CONFIG_DIR', File.expand_path('~/.jupyter'))
14
+ File.join(jupyter_config_dir, 'data')
15
+ end
16
+ when apple?
17
+ File.expand_path('~/Library/Jupyter')
18
+ else
19
+ xdg_data_home = ENV.fetch('XDG_DATA_HOME', '')
20
+ data_home = xdg_data_home[0] ? xdg_data_home : File.expand_path('~/.local/share')
21
+ File.join(data_home, 'jupyter')
22
+ end
23
+ end
24
+
25
+ def kernelspec_dir(data_dir=nil)
26
+ data_dir ||= default_data_dir
27
+ File.join(data_dir, 'kernels')
28
+ end
29
+
30
+ private
31
+
32
+ # returns %APPDATA%
33
+ def windows_user_appdata
34
+ require 'fiddle/import'
35
+ check_windows
36
+ path = Fiddle::Pointer.malloc(2 * 300) # uint16_t[300]
37
+ csidl_appdata = 0x001a
38
+ case call_SHGetFolderPathW(Fiddle::NULL, csidl_appdata, Fiddle::NULL, 0, path)
39
+ when 0
40
+ len = (1 ... (path.size/2)).find {|i| path[2*i, 2] == "\0\0" }
41
+ path = path.to_str(2*len).encode(Encoding::UTF_8, Encoding::UTF_16LE)
42
+ else
43
+ ENV.fetch('APPDATA', '')
44
+ end
45
+ end
46
+
47
+ def call_SHGetFolderPathW(hwnd, csidl, hToken, dwFlags, pszPath)
48
+ require 'fiddle/import'
49
+ shell32 = Fiddle::Handle.new('shell32')
50
+ func = Fiddle::Function.new(
51
+ shell32['SHGetFolderPathW'],
52
+ [
53
+ Fiddle::TYPE_VOIDP,
54
+ Fiddle::TYPE_INT,
55
+ Fiddle::TYPE_VOIDP,
56
+ Fiddle::TYPE_INT,
57
+ Fiddle::TYPE_VOIDP
58
+ ],
59
+ Fiddle::TYPE_INT,
60
+ Fiddle::Importer.const_get(:CALL_TYPE_TO_ABI)[:stdcall])
61
+ func.(hwnd, csidl, hToken, dwFlags, pszPath)
62
+ end
63
+
64
+ def check_windows
65
+ raise 'the current platform is not Windows' unless windows?
66
+ end
67
+
68
+ def windows?
69
+ /mingw|mswin/ =~ RUBY_PLATFORM
70
+ end
71
+
72
+ def apple?
73
+ /darwin/ =~ RUBY_PLATFORM
74
+ end
75
+ end
76
+ end
77
+ end
data/lib/iruby/kernel.rb CHANGED
@@ -1,7 +1,6 @@
1
1
  module IRuby
2
2
  class Kernel
3
3
  RED = "\e[31m"
4
- WHITE = "\e[37m"
5
4
  RESET = "\e[0m"
6
5
 
7
6
  class<< self
@@ -19,6 +18,8 @@ module IRuby
19
18
  $stdout = OStream.new(@session, :stdout)
20
19
  $stderr = OStream.new(@session, :stderr)
21
20
 
21
+ init_parent_process_poller
22
+
22
23
  @execution_count = 0
23
24
  @backend = create_backend
24
25
  @running = true
@@ -40,6 +41,7 @@ module IRuby
40
41
 
41
42
  def dispatch
42
43
  msg = @session.recv(:reply)
44
+ IRuby.logger.debug "Kernel#dispatch: msg = #{msg}"
43
45
  type = msg[:header]['msg_type']
44
46
  raise "Unknown message type: #{msg.inspect}" unless type =~ /comm_|_request\Z/ && respond_to?(type)
45
47
  begin
@@ -50,24 +52,32 @@ module IRuby
50
52
  end
51
53
  rescue Exception => e
52
54
  IRuby.logger.debug "Kernel error: #{e.message}\n#{e.backtrace.join("\n")}"
53
- @session.send(:publish, :error, error_message(e))
55
+ @session.send(:publish, :error, error_content(e))
54
56
  end
55
57
 
56
58
  def kernel_info_request(msg)
57
59
  @session.send(:reply, :kernel_info_reply,
58
60
  protocol_version: '5.0',
59
61
  implementation: 'iruby',
60
- banner: "IRuby #{IRuby::VERSION}",
61
62
  implementation_version: IRuby::VERSION,
62
63
  language_info: {
63
64
  name: 'ruby',
64
65
  version: RUBY_VERSION,
65
66
  mimetype: 'application/x-ruby',
66
- file_extension: 'rb'
67
- })
67
+ file_extension: '.rb'
68
+ },
69
+ banner: "IRuby #{IRuby::VERSION} (with #{@session.description})",
70
+ help_links: [
71
+ {
72
+ text: "Ruby Documentation",
73
+ url: "https://ruby-doc.org/"
74
+ }
75
+ ],
76
+ status: :ok)
68
77
  end
69
78
 
70
79
  def send_status(status)
80
+ IRuby.logger.debug "Send status: #{status}"
71
81
  @session.send(:publish, :status, execution_state: status)
72
82
  end
73
83
 
@@ -88,8 +98,10 @@ module IRuby
88
98
  rescue SystemExit
89
99
  content[:payload] << { source: :ask_exit }
90
100
  rescue Exception => e
91
- content = error_message(e)
101
+ content = error_content(e)
92
102
  @session.send(:publish, :error, content)
103
+ content[:status] = :error
104
+ content[:execution_count] = @execution_count
93
105
  end
94
106
  @session.send(:reply, :execute_reply, content)
95
107
  @session.send(:publish, :execute_result,
@@ -98,26 +110,33 @@ module IRuby
98
110
  execution_count: @execution_count) unless result.nil? || msg[:content]['silent']
99
111
  end
100
112
 
101
- def error_message(e)
102
- { status: :error,
103
- ename: e.class.to_s,
113
+ def error_content(e)
114
+ rindex = e.backtrace.rindex{|line| line.start_with?(@backend.eval_path)} || -1
115
+ backtrace = SyntaxError === e && rindex == -1 ? [] : e.backtrace[0..rindex]
116
+ { ename: e.class.to_s,
104
117
  evalue: e.message,
105
- traceback: ["#{RED}#{e.class}#{RESET}: #{e.message}", *e.backtrace.map { |l| "#{WHITE}#{l}#{RESET}" }],
106
- execution_count: @execution_count }
118
+ traceback: ["#{RED}#{e.class}#{RESET}: #{e.message}", *backtrace] }
119
+ end
120
+
121
+ def is_complete_request(msg)
122
+ # FIXME: the code completeness should be judged by using ripper or other Ruby parser
123
+ @session.send(:reply, :is_complete_reply,
124
+ status: :unknown)
107
125
  end
108
126
 
109
127
  def complete_request(msg)
110
128
  # HACK for #26, only complete last line
111
129
  code = msg[:content]['code']
112
- if start = code.rindex("\n")
130
+ if start = code.rindex(/\s|\R/)
113
131
  code = code[start+1..-1]
114
132
  start += 1
115
133
  end
116
134
  @session.send(:reply, :complete_reply,
117
135
  matches: @backend.complete(code),
118
- status: :ok,
119
136
  cursor_start: start.to_i,
120
- cursor_end: msg[:content]['cursor_pos'])
137
+ cursor_end: msg[:content]['cursor_pos'],
138
+ metadata: {},
139
+ status: :ok)
121
140
  end
122
141
 
123
142
  def connect_request(msg)
@@ -136,14 +155,8 @@ module IRuby
136
155
  end
137
156
 
138
157
  def inspect_request(msg)
139
- result = @backend.eval(msg[:content]['code'])
140
- @session.send(:reply, :inspect_reply,
141
- status: :ok,
142
- data: Display.display(result),
143
- metadata: {})
144
- rescue Exception => e
145
- IRuby.logger.warn "Inspection error: #{e.message}\n#{e.backtrace.join("\n")}"
146
- @session.send(:reply, :inspect_reply, status: :error)
158
+ # not yet implemented. See (#119).
159
+ @session.send(:reply, :inspect_reply, status: :ok, found: false, data: {}, metadata: {})
147
160
  end
148
161
 
149
162
  def comm_open(msg)
@@ -161,5 +174,37 @@ module IRuby
161
174
  Comm.comm[comm_id].handle_close(msg[:content]['data'])
162
175
  Comm.comm.delete(comm_id)
163
176
  end
177
+
178
+ private
179
+
180
+ def init_parent_process_poller
181
+ pid = ENV.fetch('JPY_PARENT_PID', 0).to_i
182
+ return unless pid > 1
183
+
184
+ case RUBY_PLATFORM
185
+ when /mswin/, /mingw/
186
+ # TODO
187
+ else
188
+ @parent_poller = start_parent_process_pollar_unix
189
+ end
190
+ end
191
+
192
+ def start_parent_process_pollar_unix
193
+ Thread.start do
194
+ IRuby.logger.warn("parent process poller thread started.")
195
+ loop do
196
+ begin
197
+ current_ppid = Process.ppid
198
+ if current_ppid == 1
199
+ IRuby.logger.warn("parent process appears to exited, shutting down.")
200
+ exit!(1)
201
+ end
202
+ sleep 1
203
+ rescue Errno::EINTR
204
+ # ignored
205
+ end
206
+ end
207
+ end
208
+ end
164
209
  end
165
210
  end
data/lib/iruby/ostream.rb CHANGED
@@ -25,22 +25,38 @@ module IRuby
25
25
  alias_method :next, :read
26
26
  alias_method :readline, :read
27
27
 
28
- def write(s)
29
- raise 'I/O operation on closed file' unless @session
30
- @session.send(:publish, :stream, name: @name, text: s.to_s)
31
- nil
28
+ def write(*obj)
29
+ str = build_string { |sio| sio.write(*obj) }
30
+ session_send(str)
32
31
  end
33
32
  alias_method :<<, :write
34
33
  alias_method :print, :write
35
34
 
36
- def puts(*lines)
37
- lines = [''] if lines.empty?
38
- lines.each { |s| write("#{s}\n")}
39
- nil
35
+ def printf(format, *obj)
36
+ str = build_string { |sio| sio.printf(format, *obj) }
37
+ session_send(str)
38
+ end
39
+
40
+ def puts(*obj)
41
+ str = build_string { |sio| sio.puts(*obj) }
42
+ session_send(str)
40
43
  end
41
44
 
42
45
  def writelines(lines)
43
46
  lines.each { |s| write(s) }
44
47
  end
48
+
49
+ private
50
+
51
+ def build_string
52
+ StringIO.open { |sio| yield(sio); sio.string }
53
+ end
54
+
55
+ def session_send(str)
56
+ raise 'I/O operation on closed file' unless @session
57
+
58
+ @session.send(:publish, :stream, name: @name, text: str)
59
+ nil
60
+ end
45
61
  end
46
62
  end
data/lib/iruby/session.rb CHANGED
@@ -1,98 +1,116 @@
1
+ require 'iruby/session_adapter'
2
+ require 'iruby/session/mixin'
3
+
4
+ require 'securerandom'
5
+
1
6
  module IRuby
2
7
  class Session
3
- DELIM = '<IDS|MSG>'
8
+ include SessionSerialize
9
+
10
+ def initialize(config, adapter_name=nil)
11
+ @config = config
12
+ @adapter = create_session_adapter(config, adapter_name)
4
13
 
5
- def initialize(config)
6
- c = ZMQ::Context.new
14
+ setup
15
+ setup_sockets
16
+ setup_heartbeat
17
+ setup_security
18
+ end
7
19
 
8
- connection = "#{config['transport']}://#{config['ip']}:%d"
9
- reply_socket = c.socket(:ROUTER)
10
- reply_socket.bind(connection % config['shell_port'])
20
+ attr_reader :adapter, :config
11
21
 
12
- pub_socket = c.socket(:PUB)
13
- pub_socket.bind(connection % config['iopub_port'])
22
+ def description
23
+ "#{@adapter.name} session adapter"
24
+ end
14
25
 
15
- Thread.new do
26
+ def setup
27
+ end
28
+
29
+ def setup_sockets
30
+ protocol, host = config.values_at('transport', 'ip')
31
+ shell_port = config['shell_port']
32
+ iopub_port = config['iopub_port']
33
+ stdin_port = config['stdin_port']
34
+
35
+ @shell_socket, @shell_port = @adapter.make_router_socket(protocol, host, shell_port)
36
+ @iopub_socket, @iopub_port = @adapter.make_pub_socket(protocol, host, iopub_port)
37
+ @stdin_socket, @stdin_port = @adapter.make_router_socket(protocol, host, stdin_port)
38
+
39
+ @sockets = {
40
+ publish: @iopub_socket,
41
+ reply: @shell_socket,
42
+ stdin: @stdin_socket
43
+ }
44
+ end
45
+
46
+ def setup_heartbeat
47
+ protocol, host = config.values_at('transport', 'ip')
48
+ hb_port = config['hb_port']
49
+ @hb_socket, @hb_port = @adapter.make_rep_socket(protocol, host, hb_port)
50
+ @heartbeat_thread = Thread.start do
16
51
  begin
17
- hb_socket = c.socket(:REP)
18
- hb_socket.bind(connection % config['hb_port'])
19
- ZMQ.proxy(hb_socket, hb_socket)
52
+ # NOTE: this loop is copied from CZTop's old session code
53
+ @adapter.heartbeat_loop(@hb_socket)
20
54
  rescue Exception => e
21
55
  IRuby.logger.fatal "Kernel heartbeat died: #{e.message}\n#{e.backtrace.join("\n")}"
22
56
  end
23
57
  end
58
+ end
24
59
 
25
- @sockets = { publish: pub_socket, reply: reply_socket }
26
- @session = SecureRandom.uuid
27
- unless config['key'].to_s.empty? || config['signature_scheme'].to_s.empty?
28
- raise 'Unknown signature scheme' unless config['signature_scheme'] =~ /\Ahmac-(.*)\Z/
29
- @hmac = OpenSSL::HMAC.new(config['key'], OpenSSL::Digest.new($1))
60
+ def setup_security
61
+ @session_id = SecureRandom.uuid
62
+ unless config['key'].empty? || config['signature_scheme'].empty?
63
+ unless config['signature_scheme'] =~ /\Ahmac-/
64
+ raise "Unknown signature_scheme: #{config['signature_scheme']}"
65
+ end
66
+ digest_algorithm = config['signature_scheme'][/\Ahmac-(.*)\Z/, 1]
67
+ @hmac = OpenSSL::HMAC.new(config['key'], OpenSSL::Digest.new(digest_algorithm))
30
68
  end
31
69
  end
32
70
 
33
- # Build and send a message
34
- def send(socket, type, content)
35
- idents =
36
- if socket == :reply && @last_recvd_msg
37
- @last_recvd_msg[:idents]
38
- else
39
- type == :stream ? "stream.#{content[:name]}" : type
40
- end
71
+ def send(socket_type, message_type, content)
72
+ sock = check_socket_type(socket_type)
73
+ idents = if socket_type == :reply && @last_recvd_msg
74
+ @last_recvd_msg[:idents]
75
+ else
76
+ message_type == :stream ? "stream.#{content[:name]}" : message_type
77
+ end
41
78
  header = {
42
- msg_type: type,
79
+ msg_type: message_type,
43
80
  msg_id: SecureRandom.uuid,
44
81
  username: 'kernel',
45
- session: @session,
82
+ session: @session_id,
46
83
  version: '5.0'
47
84
  }
48
- @sockets[socket].send_message(serialize(idents, header, content))
85
+ @adapter.send(sock, serialize(idents, header, content))
49
86
  end
50
87
 
51
- # Receive a message and decode it
52
- def recv(socket)
53
- @last_recvd_msg = unserialize(@sockets[socket].recv_message)
88
+ def recv(socket_type)
89
+ sock = check_socket_type(socket_type)
90
+ data = @adapter.recv(sock)
91
+ @last_recvd_msg = unserialize(data)
54
92
  end
55
93
 
56
- private
57
-
58
- def serialize(idents, header, content)
59
- msg = [MultiJson.dump(header),
60
- MultiJson.dump(@last_recvd_msg ? @last_recvd_msg[:header] : {}),
61
- '{}',
62
- MultiJson.dump(content || {})]
63
- frames = ([*idents].compact.map(&:to_s) << DELIM << sign(msg)) + msg
64
- IRuby.logger.debug "Sent #{frames.inspect}"
65
- ZMQ::Message(*frames)
94
+ def recv_input
95
+ sock = check_socket_type(:stdin)
96
+ data = @adapter.recv(sock)
97
+ unserialize(data)[:content]["value"]
66
98
  end
67
99
 
68
- def unserialize(msg)
69
- raise 'no message received' unless msg
70
- frames = msg.to_a.map(&:to_s)
71
- IRuby.logger.debug "Received #{frames.inspect}"
72
-
73
- i = frames.index(DELIM)
74
- idents, msg_list = frames[0..i-1], frames[i+1..-1]
75
-
76
- minlen = 5
77
- raise 'malformed message, must have at least #{minlen} elements' unless msg_list.length >= minlen
78
- s, header, parent_header, metadata, content, buffers = *msg_list
79
- raise 'Invalid signature' unless s == sign(msg_list[1..-1])
80
- {
81
- idents: idents,
82
- header: MultiJson.load(header),
83
- parent_header: MultiJson.load(parent_header),
84
- metadata: MultiJson.load(metadata),
85
- content: MultiJson.load(content),
86
- buffers: buffers
87
- }
100
+ private
101
+
102
+ def check_socket_type(socket_type)
103
+ case socket_type
104
+ when :publish, :reply, :stdin
105
+ @sockets[socket_type]
106
+ else
107
+ raise ArgumentError, "Invalid socket type #{socket_type}"
108
+ end
88
109
  end
89
110
 
90
- # Sign using HMAC
91
- def sign(list)
92
- return '' unless @hmac
93
- @hmac.reset
94
- list.each {|m| @hmac.update(m) }
95
- @hmac.hexdigest
111
+ def create_session_adapter(config, adapter_name)
112
+ adapter_class = SessionAdapter.select_adapter_class(adapter_name)
113
+ adapter_class.new(config)
96
114
  end
97
115
  end
98
116
  end