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,299 @@
1
+
2
+ # IRuby Input
3
+
4
+ This README is generated from README.ipynb. Please do not edit this file directly.
5
+
6
+ The `IRuby::Input` class makes it easier for IRuby users to get input from users. For example:
7
+
8
+
9
+ ```ruby
10
+ name = IRuby.input 'Enter your name'
11
+ ```
12
+
13
+ The following input methods are supported on the `IRuby` module:
14
+
15
+ | method | description |
16
+ | -------- | -------- |
17
+ | `input(prompt)` | Prompts the user for a line of input |
18
+ | `password(prompt)` | Prompts the user for a password |
19
+ | `form(&block)` | Presents a form to the user |
20
+ | `popup(title,&block)` | Displays a form to the user as a popup |
21
+
22
+ ## Forms
23
+
24
+ Forms are groups of inputs to be collected from the user. For example:
25
+
26
+
27
+ ```ruby
28
+ result = IRuby.form do
29
+ input :username
30
+ password :password
31
+ button
32
+ end
33
+ ```
34
+
35
+ The following methods are available to build forms:
36
+
37
+ | method | description |
38
+ | -------- | -------- |
39
+ | `input(key=:input)` | Prompts the user for a line of input |
40
+ | `textarea(key=:textarea),` | Adds a textarea to the form |
41
+ | `password(key=:password)` | Prompts the user for a password |
42
+ | `button(key=:done, color: :blue)` | Adds a submit button to the form |
43
+ | `cancel(prompt='Cancel')` | Adds a cancel button to the form |
44
+ | `text(string)` | Adds text to the form |
45
+ | `html(&block)` | Inserts HTML from the given [erector block](https://github.com/erector/erector) |
46
+ | `file(key=:file)` | Adds a file input to the form |
47
+ | `date(key=:date)` | Adds a date picker to the form |
48
+ | `select(*options)` | Adds a dropdown select input to the form |
49
+ | `radio(*options)` | Adds a radio select input to the form |
50
+ | `checkbox(*options)` | Adds checkbox inputs to the form |
51
+
52
+ ## Popups
53
+
54
+ Popups are just forms in a bootstrap modal. They are useful when users **Run All** in a notebook with a lot of inputs. The popups always appear in the same spot, so users don't have to scroll down to find the next input.
55
+
56
+ Popups accept a `title` argument, for example:
57
+
58
+
59
+ ```ruby
60
+ result = IRuby.popup 'Please enter your name' do
61
+ input
62
+ button
63
+ end
64
+ ```
65
+
66
+ ## Submit and cancel
67
+
68
+ The enter key will submit an input or form and the escape key will cancel it. Canceled inputs are returned as `nil`. Inputs are automatically canceled if destroyed. An input can be destroyed by clearing its cell's output. The `cancel` button will cancel a form and all other buttons will submit it.
69
+
70
+ After a form destroyed, the cell's output is cleared. Be careful not to prompt for input in a block that has previous output you would like to keep. Output is cleared to prevent forms from interferring with one another and to ensure that inputs are not inadvertently saved to the notebook.
71
+
72
+
73
+ ```ruby
74
+ result = IRuby.popup 'Confirm' do
75
+ text 'Are you sure you want to continue?'
76
+ cancel 'No'
77
+ button 'Yes'
78
+ end
79
+ ```
80
+
81
+ ## Custom keys
82
+
83
+ Every widget has an entry in the final results hash. A custom key can be passed as the first parameter to the hash. If no key is provided, the widget name is used as the key. The `cancel` widget has no key; it's first parameter is its label.
84
+
85
+
86
+ ```ruby
87
+ result = IRuby.form do
88
+ input :username
89
+ password :password
90
+ end
91
+ ```
92
+
93
+ ## Custom labels
94
+
95
+ Field labels appear to the left of the field. Button labels appear as the text on the button. `cancel` labels are passed as the first argument. All other widgets' labels are set using the `label` parameter.
96
+
97
+
98
+ ```ruby
99
+ result = IRuby.form do
100
+ input :name, label: 'Please enter your name'
101
+ cancel 'None of your business!'
102
+ button :submit, label: 'All done'
103
+ end
104
+ ```
105
+
106
+ ## Defaults
107
+
108
+ Most inputs will accept a `default` parameter. If no default is given, the deault is `nil`. Since checkboxes can have multiple values selected, you can pass an array of values. To check everything, pass `true` as the default.
109
+
110
+
111
+ ```ruby
112
+ result = IRuby.form do
113
+ checkbox :one, 'Fish', 'Cat', 'Dog', default: 'Fish'
114
+ checkbox :many, 'Fish', 'Cat', 'Dog', default: ['Cat', 'Dog']
115
+ checkbox :all, 'Fish', 'Cat', 'Dog', default: true
116
+ button :submit, label: 'All done'
117
+ end
118
+ ```
119
+
120
+ ## Dates
121
+
122
+ The `date` widget provides a calendar popup and returns a `Time` object. It's default should also be a `Time` object.
123
+
124
+
125
+ ```ruby
126
+ result = IRuby.form do
127
+ date :birthday
128
+ date :today, default: Time.now
129
+ button
130
+ end
131
+ ```
132
+
133
+ ## Buttons
134
+
135
+ Buttons do not appear in the final hash unless they are clicked. If clicked, their value is `true`. Here are the various colors a button can be:
136
+
137
+
138
+ ```ruby
139
+ result = IRuby.form do
140
+ IRuby::Input::Button::COLORS.each_key do |color|
141
+ button color, color: color
142
+ end
143
+ end
144
+ ```
145
+
146
+ ## Textareas
147
+
148
+ Textareas are multiline inputs that are convenient for larger inputs. If you need a line return when typing in a textarea, use shift+enter since enter will submit the form.
149
+
150
+
151
+ ```ruby
152
+ result = IRuby.form do
153
+ text 'Enter email addresses, one per line (use shift+enter for newlines)'
154
+ textarea :emails
155
+ end
156
+ ```
157
+
158
+ ## Text and HTML
159
+
160
+ You can insert lines of text or custom html using their respective helpers:
161
+
162
+
163
+ ```ruby
164
+ result = IRuby.form do
165
+ html { h1 'Choose a Stooge' }
166
+ text 'Choose your favorite stooge'
167
+ select :stooge, 'Moe', 'Larry', 'Curly'
168
+ button
169
+ end
170
+ ```
171
+
172
+ ## Dropdowns
173
+
174
+ A `select` is a dropdown of options. Use a `multiple` to allow multiple selections. `multiple` widgets accept an additional `size` parameters that determines the number of rows. The default is 4.
175
+
176
+
177
+ ```ruby
178
+ result = IRuby.form do
179
+ select :stooge, 'Moe', 'Larry', 'Curly'
180
+ select :stooge, 'Moe', 'Larry', 'Curly', default: 'Moe'
181
+ multiple :stooges, 'Moe', 'Larry', 'Curly', default: true, size: 3
182
+ multiple :stooges, 'Moe', 'Larry', 'Curly', default: ['Moe','Curly']
183
+ button
184
+ end
185
+ ```
186
+
187
+ ## Radio selects and checkboxes
188
+
189
+ Like selects, radio selects and checkboxes take multiple arguments, each one an option. If the first argument is a symbol, it is used as the key.
190
+
191
+ Note that the `checkbox` widget will always return `nil` or an array.
192
+
193
+
194
+ ```ruby
195
+ result = IRuby.form do
196
+ radio :children, *(0..12), label: 'How many children do you have?'
197
+ checkbox :gender, 'Male', 'Female', 'Intersex', label: 'Select the genders of your children'
198
+ button
199
+ end
200
+ ```
201
+
202
+ ## Files
203
+
204
+ Since file widgets capture the enter key, you should include a button when creating forms that contain only a file input:
205
+
206
+
207
+ ```ruby
208
+ IRuby.form do
209
+ file :avatar, label: 'Choose an Avatar'
210
+ button :submit
211
+ end
212
+ ```
213
+
214
+ File widgets return a hash with three keys:
215
+
216
+ * `data`: The contents of the file as a string
217
+ * `content_type`: The type of file, such as `text/plain` or `image/jpeg`
218
+ * `name`: The name of the uploaded file
219
+
220
+ ## Example
221
+
222
+ Here is an example form that uses every built-in widget.
223
+
224
+
225
+ ```ruby
226
+ result = IRuby.form do
227
+ html { h1 'The Everything Form' }
228
+ text 'Marvel at the strange and varied inputs!'
229
+ date
230
+ file
231
+ input :username
232
+ password
233
+ textarea
234
+ radio *(1..10)
235
+ checkbox 'Fish', 'Cat', 'Dog', label: 'Animals'
236
+ select :color, *IRuby::Input::Button::COLORS.keys
237
+ cancel
238
+ button
239
+ end
240
+ ```
241
+
242
+ ## Writing your own widget
243
+
244
+ Most form methods are `IRuby::Input::Widget` instances. A `Widget` is an [`Erector::Widget`](https://github.com/erector/erector) with some additional helpers. Here is the `cancel` widget:
245
+
246
+ ```ruby
247
+ module IRuby
248
+ module Input
249
+ class Cancel < Widget
250
+ needs :label
251
+
252
+ builder :cancel do |label='Cancel'|
253
+ add_button Cancel.new(label: label)
254
+ end
255
+
256
+ def widget_css
257
+ ".iruby-cancel { margin-left: 5px; }"
258
+ end
259
+
260
+ def widget_js
261
+ <<-JS
262
+ $('.iruby-cancel').click(function(){
263
+ $('#iruby-form').remove();
264
+ });
265
+ JS
266
+ end
267
+
268
+ def widget_html
269
+ button(
270
+ @label,
271
+ type: 'button',
272
+ :'data-dismiss' => 'modal',
273
+ class: "btn btn-danger pull-right iruby-cancel"
274
+ )
275
+ end
276
+ end
277
+ end
278
+ end
279
+ ```
280
+
281
+ The following methods are available for widgets to use or override:
282
+
283
+ | method | description |
284
+ | -------- | -------- |
285
+ | `widget_js` | Returns the widget's Javascript |
286
+ | `widget_css` | Returns the widget's CSS |
287
+ | `widget_html` | Returns the widget's |
288
+ | `builder(method,&block)` | Class method to add form building helpers. |
289
+
290
+ The following methods are available in the `builder` block:
291
+
292
+ | method | description |
293
+ | -------- | -------- |
294
+ | `add_field(field)` | Adds a widget to the form's field area |
295
+ | `add_button(button)` | Adds a button to the form's button area |
296
+ | `process(key,&block)` | Register a custom processing block for the given key in the results hash |
297
+ | `unique_key(key)` | Returns a unique key for the given key. Use this to make sure that there are no key collisions in the final results hash. |
298
+
299
+ A canceled form always returns `nil`. Otherwise, the form collects any element with a `data-iruby-key` and non-falsey `data-iruby-value` and passes those to the processor proc registered for the key. See the `File` widget for a more involved example of processing results.
@@ -0,0 +1,25 @@
1
+ begin
2
+ require 'erector'
3
+ rescue LoadError
4
+ raise LoadError, <<-ERROR.gsub(/\s+/,' ')
5
+ IRuby::Input requires the erector gem.
6
+ `gem install erector` or add `gem 'erector'`
7
+ it to your Gemfile to continue.
8
+ ERROR
9
+ end
10
+
11
+ require 'iruby/input/builder'
12
+ require 'iruby/input/widget'
13
+ require 'iruby/input/form'
14
+ require 'iruby/input/label'
15
+ require 'iruby/input/field'
16
+ require 'iruby/input/popup'
17
+ require 'iruby/input/button'
18
+ require 'iruby/input/cancel'
19
+ require 'iruby/input/file'
20
+ require 'iruby/input/select'
21
+ require 'iruby/input/checkbox'
22
+ require 'iruby/input/radio'
23
+ require 'iruby/input/textarea'
24
+ require 'iruby/input/date'
25
+ require 'iruby/input/multiple'
@@ -0,0 +1,67 @@
1
+ module IRuby
2
+ module Input
3
+ class Builder
4
+ attr_reader :fields, :buttons
5
+
6
+ def initialize &block
7
+ @processors = {}
8
+ @fields, @buttons = [], []
9
+ instance_eval &block
10
+ end
11
+
12
+ def add_field field
13
+ @fields << field
14
+ end
15
+
16
+ def add_button button
17
+ # see bit.ly/1Tsv6x4
18
+ @buttons.unshift button
19
+ end
20
+
21
+ def html &block
22
+ add_field Class.new(Widget) {
23
+ define_method(:widget_html) { instance_eval &block }
24
+ }.new
25
+ end
26
+
27
+ def text string
28
+ html { label string }
29
+ end
30
+
31
+ def password key='password', **params
32
+ input key, **params.merge(type: 'password')
33
+ end
34
+
35
+ def process_result result
36
+ unless result.nil?
37
+ result.each_with_object({}) do |(k,v),h|
38
+ if @processors.has_key? k
39
+ @processors[k].call h, k, v
40
+ else
41
+ h[k.to_sym] = v
42
+ end
43
+ end
44
+ end
45
+ end
46
+
47
+ private
48
+
49
+ def process key, &block
50
+ @processors[key.to_s] = block
51
+ end
52
+
53
+ def unique_key key
54
+ @keys ||= []
55
+
56
+ if @keys.include? key
57
+ (2..Float::INFINITY).each do |i|
58
+ test = "#{key}#{i}"
59
+ break key = test unless @keys.include? test
60
+ end
61
+ end
62
+
63
+ @keys << key; key
64
+ end
65
+ end
66
+ end
67
+ end
@@ -0,0 +1,47 @@
1
+ module IRuby
2
+ module Input
3
+ # extend the label class for the to_label helper
4
+ class Button < Label
5
+ needs color: :blue, js_class: 'iruby-button'
6
+
7
+ COLORS = {
8
+ blue: 'primary',
9
+ gray: 'secondary',
10
+ green: 'success',
11
+ aqua: 'info',
12
+ orange: 'warning',
13
+ red: 'danger',
14
+ none: 'link'
15
+ }
16
+
17
+ COLORS.default = 'primary'
18
+
19
+ builder :button do |key='done', **params|
20
+ params[:key] = unique_key(key)
21
+ add_button Button.new(**params)
22
+ end
23
+
24
+ def widget_css
25
+ ".#{@js_class} { margin-left: 5px; }"
26
+ end
27
+
28
+ def widget_js
29
+ <<-JS
30
+ $('.iruby-button').click(function(){
31
+ $(this).data('iruby-value', true);
32
+ $('#iruby-form').submit();
33
+ });
34
+ JS
35
+ end
36
+
37
+ def widget_html
38
+ button(
39
+ @label || to_label(@key),
40
+ type: 'button',
41
+ :'data-iruby-key' => @key,
42
+ class: "btn btn-#{COLORS[@color]} pull-right #{@js_class}"
43
+ )
44
+ end
45
+ end
46
+ end
47
+ end
@@ -0,0 +1,32 @@
1
+ module IRuby
2
+ module Input
3
+ class Cancel < Widget
4
+ needs :label
5
+
6
+ builder :cancel do |label='Cancel'|
7
+ add_button Cancel.new(label: label)
8
+ end
9
+
10
+ def widget_css
11
+ ".iruby-cancel { margin-left: 5px; }"
12
+ end
13
+
14
+ def widget_js
15
+ <<-JS
16
+ $('.iruby-cancel').click(function(){
17
+ $('#iruby-form').remove();
18
+ });
19
+ JS
20
+ end
21
+
22
+ def widget_html
23
+ button(
24
+ @label,
25
+ type: 'button',
26
+ :'data-dismiss' => 'modal',
27
+ class: "btn btn-danger pull-right iruby-cancel"
28
+ )
29
+ end
30
+ end
31
+ end
32
+ end