iruby 0.2.7 → 0.5.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 +5 -5
- data/.github/workflows/ubuntu.yml +62 -0
- data/CHANGES +62 -0
- data/Gemfile +3 -1
- data/LICENSE +1 -1
- data/README.md +148 -27
- data/Rakefile +36 -10
- data/ci/Dockerfile.base.erb +41 -0
- data/ci/Dockerfile.main.erb +7 -0
- data/ci/requirements.txt +1 -0
- data/docker/setup.sh +15 -0
- data/docker/test.sh +7 -0
- data/iruby.gemspec +14 -18
- data/lib/iruby.rb +19 -3
- data/lib/iruby/backend.rb +22 -2
- data/lib/iruby/command.rb +76 -13
- data/lib/iruby/display.rb +69 -39
- data/lib/iruby/formatter.rb +5 -4
- data/lib/iruby/input.rb +41 -0
- data/lib/iruby/input/README.ipynb +502 -0
- data/lib/iruby/input/README.md +299 -0
- data/lib/iruby/input/autoload.rb +25 -0
- data/lib/iruby/input/builder.rb +67 -0
- data/lib/iruby/input/button.rb +47 -0
- data/lib/iruby/input/cancel.rb +32 -0
- data/lib/iruby/input/checkbox.rb +74 -0
- data/lib/iruby/input/date.rb +37 -0
- data/lib/iruby/input/field.rb +31 -0
- data/lib/iruby/input/file.rb +57 -0
- data/lib/iruby/input/form.rb +77 -0
- data/lib/iruby/input/label.rb +27 -0
- data/lib/iruby/input/multiple.rb +76 -0
- data/lib/iruby/input/popup.rb +41 -0
- data/lib/iruby/input/radio.rb +59 -0
- data/lib/iruby/input/select.rb +59 -0
- data/lib/iruby/input/textarea.rb +23 -0
- data/lib/iruby/input/widget.rb +34 -0
- data/lib/iruby/jupyter.rb +77 -0
- data/lib/iruby/kernel.rb +67 -22
- data/lib/iruby/ostream.rb +24 -8
- data/lib/iruby/session.rb +85 -67
- data/lib/iruby/session/cztop.rb +70 -0
- data/lib/iruby/session/ffi_rzmq.rb +87 -0
- data/lib/iruby/session/mixin.rb +47 -0
- data/lib/iruby/session_adapter.rb +66 -0
- data/lib/iruby/session_adapter/cztop_adapter.rb +45 -0
- data/lib/iruby/session_adapter/ffirzmq_adapter.rb +55 -0
- data/lib/iruby/session_adapter/pyzmq_adapter.rb +77 -0
- data/lib/iruby/utils.rb +5 -2
- data/lib/iruby/version.rb +1 -1
- data/run-test.sh +12 -0
- data/tasks/ci.rake +65 -0
- data/test/helper.rb +90 -0
- data/test/integration_test.rb +22 -11
- data/test/iruby/backend_test.rb +37 -0
- data/test/iruby/command_test.rb +207 -0
- data/test/iruby/jupyter_test.rb +27 -0
- data/test/iruby/mime_test.rb +32 -0
- data/test/iruby/multi_logger_test.rb +1 -2
- data/test/iruby/session_adapter/cztop_adapter_test.rb +20 -0
- data/test/iruby/session_adapter/ffirzmq_adapter_test.rb +20 -0
- data/test/iruby/session_adapter/session_adapter_test_base.rb +27 -0
- data/test/iruby/session_adapter_test.rb +91 -0
- data/test/iruby/session_test.rb +47 -0
- data/test/run-test.rb +18 -0
- metadata +130 -46
- data/.travis.yml +0 -16
- data/CONTRIBUTORS +0 -19
- data/test/test_helper.rb +0 -5
@@ -0,0 +1,74 @@
|
|
1
|
+
module IRuby
|
2
|
+
module Input
|
3
|
+
class Checkbox < Label
|
4
|
+
needs :options, :default
|
5
|
+
|
6
|
+
builder :checkbox do |*args, **params|
|
7
|
+
key = :checkbox
|
8
|
+
key, *args = args if args.first.is_a? Symbol
|
9
|
+
|
10
|
+
params[:key] = unique_key(key)
|
11
|
+
params[:options] = args
|
12
|
+
|
13
|
+
params[:default] = case params[:default]
|
14
|
+
when false, nil
|
15
|
+
[]
|
16
|
+
when true
|
17
|
+
[*params[:options]]
|
18
|
+
else
|
19
|
+
[*params[:default]]
|
20
|
+
end
|
21
|
+
|
22
|
+
add_field Checkbox.new(**params)
|
23
|
+
end
|
24
|
+
|
25
|
+
def widget_css
|
26
|
+
<<-CSS
|
27
|
+
.iruby-checkbox.form-control { display: inline-table; }
|
28
|
+
.iruby-checkbox .checkbox-inline { margin: 0 15px 0 0; }
|
29
|
+
CSS
|
30
|
+
end
|
31
|
+
|
32
|
+
def widget_js
|
33
|
+
<<-JS
|
34
|
+
$('.iruby-checkbox input').change(function(){
|
35
|
+
var parent = $(this).closest('.iruby-checkbox');
|
36
|
+
$(parent).data('iruby-value', []);
|
37
|
+
|
38
|
+
$(parent).find(':checked').each(function(){
|
39
|
+
$(parent).data('iruby-value').push($(this).val());
|
40
|
+
});
|
41
|
+
|
42
|
+
if ($(parent).data('iruby-value').length == 0) {
|
43
|
+
$(parent).data('iruby-value', null);
|
44
|
+
}
|
45
|
+
});
|
46
|
+
|
47
|
+
$('.iruby-checkbox input').trigger('change');
|
48
|
+
JS
|
49
|
+
end
|
50
|
+
|
51
|
+
def widget_html
|
52
|
+
params = {
|
53
|
+
:'data-iruby-key' => @key,
|
54
|
+
class: 'iruby-checkbox form-control'
|
55
|
+
}
|
56
|
+
widget_label do
|
57
|
+
div **params do
|
58
|
+
@options.each do |option|
|
59
|
+
label class: 'checkbox-inline' do
|
60
|
+
input(
|
61
|
+
name: @key,
|
62
|
+
value: option,
|
63
|
+
type: 'checkbox',
|
64
|
+
checked: @default.include?(option)
|
65
|
+
)
|
66
|
+
text option
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
module IRuby
|
2
|
+
module Input
|
3
|
+
class Date < Field
|
4
|
+
needs js_class: 'iruby-date', icon: '📅'
|
5
|
+
|
6
|
+
builder :date do |key='date', **params|
|
7
|
+
params[:default] ||= false
|
8
|
+
params[:key] = unique_key key
|
9
|
+
|
10
|
+
if params[:default].is_a? Time
|
11
|
+
params[:default] = params[:default].strftime('%m/%d/%Y')
|
12
|
+
end
|
13
|
+
|
14
|
+
add_field Date.new(**params)
|
15
|
+
|
16
|
+
process params[:key] do |result,key,value|
|
17
|
+
result[key.to_sym] = Time.strptime(value,'%m/%d/%Y')
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
def widget_css
|
22
|
+
'#ui-datepicker-div { z-index: 2000 !important; }'
|
23
|
+
end
|
24
|
+
|
25
|
+
def widget_js
|
26
|
+
<<-JS
|
27
|
+
$('.iruby-date').datepicker({
|
28
|
+
dateFormat: 'mm/dd/yy',
|
29
|
+
onClose: function(date) {
|
30
|
+
$(this).data('iruby-value', date);
|
31
|
+
}
|
32
|
+
});
|
33
|
+
JS
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
module IRuby
|
2
|
+
module Input
|
3
|
+
class Field < Label
|
4
|
+
needs default: nil, type: 'text', js_class: 'iruby-field'
|
5
|
+
|
6
|
+
builder :input do |key='input', **params|
|
7
|
+
params[:key] = unique_key key
|
8
|
+
add_field Field.new(**params)
|
9
|
+
end
|
10
|
+
|
11
|
+
def widget_js
|
12
|
+
<<-JS
|
13
|
+
$('.iruby-field').keyup(function() {
|
14
|
+
$(this).data('iruby-value', $(this).val());
|
15
|
+
});
|
16
|
+
JS
|
17
|
+
end
|
18
|
+
|
19
|
+
def widget_html
|
20
|
+
widget_label do
|
21
|
+
input(
|
22
|
+
type: @type,
|
23
|
+
:'data-iruby-key' => @key,
|
24
|
+
class: "form-control #{@js_class}",
|
25
|
+
value: @default
|
26
|
+
)
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
@@ -0,0 +1,57 @@
|
|
1
|
+
require 'data_uri'
|
2
|
+
|
3
|
+
module IRuby
|
4
|
+
module Input
|
5
|
+
class File < Label
|
6
|
+
builder :file do |key='file', **params|
|
7
|
+
key = unique_key key
|
8
|
+
add_field File.new(key: key, **params)
|
9
|
+
|
10
|
+
# tell the builder to process files differently
|
11
|
+
process key do |result,key,value|
|
12
|
+
uri = URI::Data.new value['data']
|
13
|
+
|
14
|
+
# get rid of Chrome's silly path
|
15
|
+
name = value['name'].sub('C:\\fakepath\\','')
|
16
|
+
|
17
|
+
result[key.to_sym] = {
|
18
|
+
name: name,
|
19
|
+
data: uri.data,
|
20
|
+
content_type: uri.content_type
|
21
|
+
}
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
def widget_js
|
26
|
+
<<-JS
|
27
|
+
$('.iruby-file').change(function() {
|
28
|
+
var input = $(this);
|
29
|
+
|
30
|
+
$.grep($(this).prop('files'), function(file) {
|
31
|
+
var reader = new FileReader();
|
32
|
+
|
33
|
+
reader.addEventListener("load", function(event) {
|
34
|
+
input.data('iruby-value', {
|
35
|
+
name: input.val(),
|
36
|
+
data: event.target.result
|
37
|
+
});
|
38
|
+
});
|
39
|
+
|
40
|
+
reader.readAsDataURL(file);
|
41
|
+
});
|
42
|
+
});
|
43
|
+
JS
|
44
|
+
end
|
45
|
+
|
46
|
+
def widget_html
|
47
|
+
widget_label do
|
48
|
+
input(
|
49
|
+
type: 'file',
|
50
|
+
:'data-iruby-key' => @key,
|
51
|
+
class: 'form-control iruby-file'
|
52
|
+
)
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
@@ -0,0 +1,77 @@
|
|
1
|
+
require 'securerandom'
|
2
|
+
|
3
|
+
module IRuby
|
4
|
+
module Input
|
5
|
+
class InputForm < Widget
|
6
|
+
needs :fields, buttons: []
|
7
|
+
|
8
|
+
def widget_js
|
9
|
+
javascript = <<-JS
|
10
|
+
var remove = function () {
|
11
|
+
Jupyter.notebook.kernel.send_input_reply(
|
12
|
+
JSON.stringify({
|
13
|
+
'#{@id = SecureRandom.uuid}': null
|
14
|
+
})
|
15
|
+
);
|
16
|
+
};
|
17
|
+
|
18
|
+
$("#iruby-form").on("remove", remove);
|
19
|
+
|
20
|
+
$('#iruby-form').submit(function() {
|
21
|
+
var result = {};
|
22
|
+
$(this).off('remove', remove);
|
23
|
+
|
24
|
+
$('[data-iruby-key]').each(function() {
|
25
|
+
if ($(this).data('iruby-key')) {
|
26
|
+
var value = $(this).data('iruby-value');
|
27
|
+
if (value) {
|
28
|
+
result[$(this).data('iruby-key')] = value;
|
29
|
+
}
|
30
|
+
}
|
31
|
+
});
|
32
|
+
|
33
|
+
Jupyter.notebook.kernel.send_input_reply(
|
34
|
+
JSON.stringify({'#{@id}': result})
|
35
|
+
);
|
36
|
+
|
37
|
+
$(this).remove();
|
38
|
+
return false;
|
39
|
+
});
|
40
|
+
|
41
|
+
$('#iruby-form').keydown(function(event) {
|
42
|
+
if (event.keyCode == 13 && !event.shiftKey) {
|
43
|
+
$('#iruby-form').submit();
|
44
|
+
} else if (event.keyCode == 27) {
|
45
|
+
$('#iruby-form').remove();
|
46
|
+
}
|
47
|
+
});
|
48
|
+
JS
|
49
|
+
|
50
|
+
widget_join :widget_js, javascript, *@fields, *@buttons
|
51
|
+
end
|
52
|
+
|
53
|
+
def widget_css
|
54
|
+
spacing = '#iruby-form > * { margin-bottom: 5px; }'
|
55
|
+
widget_join :widget_css, spacing, *@fields, *@buttons
|
56
|
+
end
|
57
|
+
|
58
|
+
def widget_html
|
59
|
+
form id: 'iruby-form', class: 'col-md-12' do
|
60
|
+
@fields.each {|field| widget field}
|
61
|
+
end
|
62
|
+
@buttons.each {|button| widget button}
|
63
|
+
end
|
64
|
+
|
65
|
+
def submit
|
66
|
+
result = MultiJson.load(Kernel.instance.session.recv_input)
|
67
|
+
|
68
|
+
unless result.has_key? @id
|
69
|
+
submit
|
70
|
+
else
|
71
|
+
Display.clear_output
|
72
|
+
result[@id]
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
module IRuby
|
2
|
+
module Input
|
3
|
+
class Label < Widget
|
4
|
+
needs label: nil, icon: nil
|
5
|
+
|
6
|
+
def widget_label
|
7
|
+
div class: 'iruby-label input-group' do
|
8
|
+
span class: 'input-group-addon' do
|
9
|
+
text @label || to_label(@key)
|
10
|
+
end
|
11
|
+
|
12
|
+
yield
|
13
|
+
|
14
|
+
if @icon
|
15
|
+
span @icon, class: "input-group-addon"
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
private
|
21
|
+
|
22
|
+
def to_label label
|
23
|
+
label.to_s.tr('_',' ').capitalize
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,76 @@
|
|
1
|
+
module IRuby
|
2
|
+
module Input
|
3
|
+
class Multiple < Label
|
4
|
+
needs :options, :default, size: nil
|
5
|
+
|
6
|
+
builder :multiple do |*args, **params|
|
7
|
+
key = :multiple
|
8
|
+
key, *args = args if args.first.is_a? Symbol
|
9
|
+
|
10
|
+
params[:key] = unique_key(key)
|
11
|
+
params[:options] = args
|
12
|
+
|
13
|
+
params[:default] = case params[:default]
|
14
|
+
when false, nil
|
15
|
+
[]
|
16
|
+
when true
|
17
|
+
[*params[:options]]
|
18
|
+
else
|
19
|
+
[*params[:default]]
|
20
|
+
end
|
21
|
+
|
22
|
+
add_field Multiple.new(**params)
|
23
|
+
end
|
24
|
+
|
25
|
+
def widget_css
|
26
|
+
<<-CSS
|
27
|
+
.iruby-multiple {
|
28
|
+
display: table;
|
29
|
+
min-width: 25%;
|
30
|
+
}
|
31
|
+
.form-control.iruby-multiple-container {
|
32
|
+
display: table;
|
33
|
+
}
|
34
|
+
CSS
|
35
|
+
end
|
36
|
+
|
37
|
+
def widget_js
|
38
|
+
<<-JS
|
39
|
+
$('.iruby-multiple').change(function(){
|
40
|
+
var multiple = $(this);
|
41
|
+
multiple.data('iruby-value', []);
|
42
|
+
|
43
|
+
multiple.find(':selected').each(function(){
|
44
|
+
multiple.data('iruby-value').push($(this).val());
|
45
|
+
});
|
46
|
+
|
47
|
+
if (multiple.data('iruby-value').length == 0) {
|
48
|
+
multiple.data('iruby-value', null);
|
49
|
+
}
|
50
|
+
});
|
51
|
+
|
52
|
+
$('.iruby-multiple').trigger('change');
|
53
|
+
JS
|
54
|
+
end
|
55
|
+
|
56
|
+
def widget_html
|
57
|
+
widget_label do
|
58
|
+
div class: 'form-control iruby-multiple-container' do
|
59
|
+
params = {
|
60
|
+
size: @size,
|
61
|
+
multiple: true,
|
62
|
+
class: 'iruby-multiple',
|
63
|
+
:'data-iruby-key' => @key
|
64
|
+
}
|
65
|
+
|
66
|
+
select **params do
|
67
|
+
@options.each do |o|
|
68
|
+
option o, selected: @default.include?(o)
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
@@ -0,0 +1,41 @@
|
|
1
|
+
module IRuby
|
2
|
+
module Input
|
3
|
+
class Popup < Widget
|
4
|
+
needs :title, :form, buttons: []
|
5
|
+
|
6
|
+
def widget_css
|
7
|
+
style = '.modal-body { overflow: auto; }'
|
8
|
+
widget_join :widget_css, style, @form, *@buttons
|
9
|
+
end
|
10
|
+
|
11
|
+
def widget_js
|
12
|
+
js = <<-JS
|
13
|
+
require(['base/js/dialog'], function(dialog) {
|
14
|
+
var popup = dialog.modal({
|
15
|
+
title: '#{@title.gsub("'"){"\\'"}}',
|
16
|
+
body: '#{@form.to_html}',
|
17
|
+
destroy: true,
|
18
|
+
sanitize: false,
|
19
|
+
keyboard_manager: Jupyter.notebook.keyboard_manager,
|
20
|
+
open: function() {
|
21
|
+
#{widget_join :widget_js, @form, *@buttons}
|
22
|
+
|
23
|
+
var popup = $(this);
|
24
|
+
|
25
|
+
$('#iruby-form').submit(function() {
|
26
|
+
popup.modal('hide');
|
27
|
+
});
|
28
|
+
|
29
|
+
Jupyter.notebook.keyboard_manager.disable();
|
30
|
+
}
|
31
|
+
});
|
32
|
+
|
33
|
+
popup.find('.modal-footer').each(function(e) {
|
34
|
+
$(this).append('#{@buttons.map(&:to_html).join}');
|
35
|
+
});
|
36
|
+
});
|
37
|
+
JS
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
@@ -0,0 +1,59 @@
|
|
1
|
+
module IRuby
|
2
|
+
module Input
|
3
|
+
class Radio < Label
|
4
|
+
needs :options, :default
|
5
|
+
|
6
|
+
builder :radio do |*args, **params|
|
7
|
+
key = :radio
|
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
|
+
add_field Radio.new(**params)
|
14
|
+
end
|
15
|
+
|
16
|
+
def widget_css
|
17
|
+
<<-CSS
|
18
|
+
.iruby-radio.form-control { display: inline-table; }
|
19
|
+
.iruby-radio .radio-inline { margin: 0 15px 0 0; }
|
20
|
+
CSS
|
21
|
+
end
|
22
|
+
|
23
|
+
def widget_js
|
24
|
+
<<-JS
|
25
|
+
$('.iruby-radio input').change(function(){
|
26
|
+
var parent = $(this).closest('.iruby-radio');
|
27
|
+
$(parent).data('iruby-value',
|
28
|
+
$(parent).find(':checked').val()
|
29
|
+
);
|
30
|
+
});
|
31
|
+
$('.iruby-radio input').trigger('change');
|
32
|
+
JS
|
33
|
+
end
|
34
|
+
|
35
|
+
def widget_html
|
36
|
+
params = {
|
37
|
+
:'data-iruby-key' => @key,
|
38
|
+
:'data-iruby-value' => @options.first,
|
39
|
+
class: 'iruby-radio form-control'
|
40
|
+
}
|
41
|
+
widget_label do
|
42
|
+
div **params do
|
43
|
+
@options.each do |option|
|
44
|
+
label class: 'radio-inline' do
|
45
|
+
input(
|
46
|
+
name: @key,
|
47
|
+
value: option,
|
48
|
+
type: 'radio',
|
49
|
+
checked: @default == option
|
50
|
+
)
|
51
|
+
text option
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|