iruby 0.2.9 → 0.6.1

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.
Files changed (72) hide show
  1. checksums.yaml +5 -5
  2. data/.github/workflows/ubuntu.yml +62 -0
  3. data/CHANGES +64 -0
  4. data/Gemfile +3 -1
  5. data/LICENSE +1 -1
  6. data/README.md +120 -92
  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 +13 -18
  14. data/lib/iruby.rb +13 -6
  15. data/lib/iruby/backend.rb +38 -9
  16. data/lib/iruby/command.rb +68 -12
  17. data/lib/iruby/display.rb +81 -41
  18. data/lib/iruby/event_manager.rb +40 -0
  19. data/lib/iruby/formatter.rb +3 -3
  20. data/lib/iruby/input.rb +6 -6
  21. data/lib/iruby/input/README.ipynb +55 -3
  22. data/lib/iruby/input/README.md +299 -0
  23. data/lib/iruby/input/autoload.rb +3 -2
  24. data/lib/iruby/input/builder.rb +4 -4
  25. data/lib/iruby/input/button.rb +2 -2
  26. data/lib/iruby/input/cancel.rb +1 -1
  27. data/lib/iruby/input/checkbox.rb +22 -4
  28. data/lib/iruby/input/date.rb +17 -6
  29. data/lib/iruby/input/field.rb +5 -4
  30. data/lib/iruby/input/file.rb +3 -3
  31. data/lib/iruby/input/form.rb +6 -6
  32. data/lib/iruby/input/label.rb +9 -3
  33. data/lib/iruby/input/multiple.rb +76 -0
  34. data/lib/iruby/input/popup.rb +5 -2
  35. data/lib/iruby/input/radio.rb +18 -6
  36. data/lib/iruby/input/select.rb +26 -12
  37. data/lib/iruby/input/textarea.rb +2 -1
  38. data/lib/iruby/input/widget.rb +2 -2
  39. data/lib/iruby/jupyter.rb +77 -0
  40. data/lib/iruby/kernel.rb +171 -31
  41. data/lib/iruby/ostream.rb +29 -8
  42. data/lib/iruby/session.rb +116 -0
  43. data/lib/iruby/session/{rbczmq.rb → cztop.rb} +21 -19
  44. data/lib/iruby/session/ffi_rzmq.rb +1 -1
  45. data/lib/iruby/session_adapter.rb +72 -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/session_adapter/test_adapter.rb +49 -0
  50. data/lib/iruby/utils.rb +13 -2
  51. data/lib/iruby/version.rb +1 -1
  52. data/run-test.sh +12 -0
  53. data/tasks/ci.rake +65 -0
  54. data/test/helper.rb +133 -0
  55. data/test/integration_test.rb +22 -11
  56. data/test/iruby/backend_test.rb +37 -0
  57. data/test/iruby/command_test.rb +207 -0
  58. data/test/iruby/event_manager_test.rb +92 -0
  59. data/test/iruby/jupyter_test.rb +27 -0
  60. data/test/iruby/kernel_test.rb +153 -0
  61. data/test/iruby/mime_test.rb +43 -0
  62. data/test/iruby/multi_logger_test.rb +1 -2
  63. data/test/iruby/session_adapter/cztop_adapter_test.rb +20 -0
  64. data/test/iruby/session_adapter/ffirzmq_adapter_test.rb +20 -0
  65. data/test/iruby/session_adapter/session_adapter_test_base.rb +27 -0
  66. data/test/iruby/session_adapter_test.rb +91 -0
  67. data/test/iruby/session_test.rb +48 -0
  68. data/test/run-test.rb +19 -0
  69. metadata +107 -50
  70. data/.travis.yml +0 -16
  71. data/CONTRIBUTORS +0 -19
  72. data/test/test_helper.rb +0 -5
@@ -0,0 +1,40 @@
1
+ module IRuby
2
+ class EventManager
3
+ def initialize(available_events)
4
+ @available_events = available_events.dup.freeze
5
+ @callbacks = available_events.map {|n| [n, []] }.to_h
6
+ end
7
+
8
+ attr_reader :available_events
9
+
10
+ def register(event, &block)
11
+ check_available_event(event)
12
+ @callbacks[event] << block unless block.nil?
13
+ block
14
+ end
15
+
16
+ def unregister(event, callback)
17
+ check_available_event(event)
18
+ val = @callbacks[event].delete(callback)
19
+ unless val
20
+ raise ArgumentError,
21
+ "Given callable object #{callback} is not registered as a #{event} callback"
22
+ end
23
+ val
24
+ end
25
+
26
+ def trigger(event, *args, **kwargs)
27
+ check_available_event(event)
28
+ @callbacks[event].each do |fn|
29
+ fn.call(*args, **kwargs)
30
+ end
31
+ end
32
+
33
+ private
34
+
35
+ def check_available_event(event)
36
+ return if @callbacks.key?(event)
37
+ raise ArgumentError, "Unknown event name: #{event}", caller
38
+ end
39
+ end
40
+ end
@@ -78,16 +78,16 @@ module IRuby
78
78
 
79
79
  if maxcols && keys.size > maxcols
80
80
  keys1 = keys[0...maxcols / 2]
81
- keys2 = keys[-maxcols / 2...-1]
81
+ keys2 = keys[-maxcols / 2 + 1..-1]
82
82
  if header
83
83
  header1 = header[0...maxcols / 2]
84
- header2 = header[-maxcols / 2...-1]
84
+ header2 = header[-maxcols / 2 + 1..-1]
85
85
  end
86
86
  end
87
87
 
88
88
  if maxrows && rows.size > maxrows
89
89
  rows1 = rows[0...maxrows / 2]
90
- rows2 = rows[-maxrows / 2...-1]
90
+ rows2 = rows[-maxrows / 2 + 1..-1]
91
91
  end
92
92
 
93
93
  table = '<table>'
data/lib/iruby/input.rb CHANGED
@@ -15,21 +15,21 @@ module IRuby
15
15
  end
16
16
 
17
17
  def form &block
18
- builder = Builder.new &block
18
+ builder = Builder.new(&block)
19
19
  form = InputForm.new(
20
- fields: builder.fields,
20
+ fields: builder.fields,
21
21
  buttons: builder.buttons
22
22
  )
23
23
  form.widget_display
24
24
  builder.process_result form.submit
25
25
  end
26
-
26
+
27
27
  def popup title='Input', &block
28
- builder = Builder.new &block
28
+ builder = Builder.new(&block)
29
29
  form = InputForm.new fields: builder.fields
30
30
  popup = Popup.new(
31
- title: title,
32
- form: form,
31
+ title: title,
32
+ form: form,
33
33
  buttons: builder.buttons
34
34
  )
35
35
  popup.widget_display
@@ -178,6 +178,55 @@
178
178
  "end"
179
179
  ]
180
180
  },
181
+ {
182
+ "cell_type": "markdown",
183
+ "metadata": {},
184
+ "source": [
185
+ "## Defaults\n",
186
+ "\n",
187
+ "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. "
188
+ ]
189
+ },
190
+ {
191
+ "cell_type": "code",
192
+ "execution_count": null,
193
+ "metadata": {
194
+ "collapsed": false
195
+ },
196
+ "outputs": [],
197
+ "source": [
198
+ "result = IRuby.form do \n",
199
+ " checkbox :one, 'Fish', 'Cat', 'Dog', default: 'Fish'\n",
200
+ " checkbox :many, 'Fish', 'Cat', 'Dog', default: ['Cat', 'Dog']\n",
201
+ " checkbox :all, 'Fish', 'Cat', 'Dog', default: true\n",
202
+ " button :submit, label: 'All done'\n",
203
+ "end"
204
+ ]
205
+ },
206
+ {
207
+ "cell_type": "markdown",
208
+ "metadata": {},
209
+ "source": [
210
+ "## Dates\n",
211
+ "\n",
212
+ "The `date` widget provides a calendar popup and returns a `Time` object. It's default should also be a `Time` object. "
213
+ ]
214
+ },
215
+ {
216
+ "cell_type": "code",
217
+ "execution_count": null,
218
+ "metadata": {
219
+ "collapsed": false
220
+ },
221
+ "outputs": [],
222
+ "source": [
223
+ "result = IRuby.form do \n",
224
+ " date :birthday\n",
225
+ " date :today, default: Time.now\n",
226
+ " button\n",
227
+ "end"
228
+ ]
229
+ },
181
230
  {
182
231
  "cell_type": "markdown",
183
232
  "metadata": {},
@@ -256,7 +305,7 @@
256
305
  "source": [
257
306
  "## Dropdowns\n",
258
307
  "\n",
259
- "Selects are dropdowns of options. By default, the first supplied option is selected. If you don't want any default value, use `nil` as the first parameter. "
308
+ "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. "
260
309
  ]
261
310
  },
262
311
  {
@@ -268,8 +317,11 @@
268
317
  "outputs": [],
269
318
  "source": [
270
319
  "result = IRuby.form do \n",
271
- " text 'Do you have a favorite Stooge?' \n",
272
- " select :stooge, nil, 'Moe', 'Larry', 'Curly'\n",
320
+ " select :stooge, 'Moe', 'Larry', 'Curly'\n",
321
+ " select :stooge, 'Moe', 'Larry', 'Curly', default: 'Moe'\n",
322
+ " multiple :stooges, 'Moe', 'Larry', 'Curly', default: true, size: 3\n",
323
+ " multiple :stooges, 'Moe', 'Larry', 'Curly', default: ['Moe','Curly']\n",
324
+ " button\n",
273
325
  "end"
274
326
  ]
275
327
  },
@@ -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.