rabbit-slide-kou-rubykaigi-2018 2018.6.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.rabbit +1 -0
- data/README.rd +47 -0
- data/Rakefile +17 -0
- data/config.yaml +22 -0
- data/images/bindings-by-gobject-introspection.svg +499 -0
- data/images/bindings-by-swig.svg +273 -0
- data/images/cairo-gc-trigger.pdf +0 -0
- data/images/cairo-no-gc-trigger.pdf +0 -0
- data/images/clear-code-rubykaigi-2018-silver-sponsor.png +0 -0
- data/images/code-party.png +0 -0
- data/images/jekyll-task-i18n-red-data-tools.gif +0 -0
- data/images/pdf-clickable.png +0 -0
- data/images/rabbit-slide-show.png +0 -0
- data/images/ruby-gtk3-with-ruby-gi.svg +411 -0
- data/images/ruby-gtk3-without-ruby-gi.svg +313 -0
- data/images/rubykaigi-2017-extension-by-cpp-title.pdf +1853 -4
- data/images/rurema-search.png +0 -0
- data/images/shocker.jpeg +0 -0
- data/images/the-tortoise-and-the-hare-fast.png +0 -0
- data/images/the-tortoise-and-the-hare-good.png +0 -0
- data/images/the-tortoise-and-the-hare-hare.png +0 -0
- data/images/the-tortoise-and-the-hare-raw.png +0 -0
- data/images/the-tortoise-and-the-hare-slow.png +0 -0
- data/images/the-tortoise-and-the-hare-tortoise.png +0 -0
- data/images/the-tortoise-and-the-hare.gif +0 -0
- data/images/the-tortoise-and-the-hare.png +0 -0
- data/interface.rab +614 -0
- data/my-way-with-ruby.rab +1668 -0
- data/pdf/rubykaigi-2018-my-way-with-ruby.pdf +0 -0
- data/theme.rb +4 -0
- metadata +108 -0
@@ -0,0 +1,1668 @@
|
|
1
|
+
= My way with Ruby
|
2
|
+
|
3
|
+
: author
|
4
|
+
Kouhei Sutou
|
5
|
+
: institution
|
6
|
+
ClearCode Inc.
|
7
|
+
: content-source
|
8
|
+
RubyKaigi 2018
|
9
|
+
: date
|
10
|
+
2018-06-01
|
11
|
+
: start-time
|
12
|
+
2018-06-01T09:40:00+09:00
|
13
|
+
: end-time
|
14
|
+
2018-06-01T10:35:00+09:00
|
15
|
+
: theme
|
16
|
+
.
|
17
|
+
|
18
|
+
= Ad: Silver sponsor
|
19
|
+
|
20
|
+
# img
|
21
|
+
# src = images/clear-code-rubykaigi-2018-silver-sponsor.png
|
22
|
+
# relative_height = 100
|
23
|
+
# reflect_ratio = 0.1
|
24
|
+
|
25
|
+
== Slide properties
|
26
|
+
|
27
|
+
: enable-title-on-image
|
28
|
+
false
|
29
|
+
|
30
|
+
= Keynote-ish topic\n(('note:キーノートっぽい話題'))
|
31
|
+
|
32
|
+
Did you think about it?\n
|
33
|
+
(('note:考えたことある?'))
|
34
|
+
|
35
|
+
= Keynote-ish topic1\n(('note:キーノートっぽい話題1'))
|
36
|
+
|
37
|
+
Future\n
|
38
|
+
(('note:未来のこと'))
|
39
|
+
|
40
|
+
= Keynote-ish topic2\n(('note:キーノートっぽい話題2'))
|
41
|
+
|
42
|
+
Focus on\n
|
43
|
+
one thing\n
|
44
|
+
((*deeply*))\n
|
45
|
+
(('note:なにかを深掘り'))
|
46
|
+
|
47
|
+
= Keynote-ish topic3\n(('note:キーノートっぽい話題3'))
|
48
|
+
|
49
|
+
Overview\n
|
50
|
+
(('note:俯瞰した話'))
|
51
|
+
|
52
|
+
= My activities\nas a Rubyist\n(('note:私のRubyist活動'))
|
53
|
+
|
54
|
+
* Increase what Ruby can\n
|
55
|
+
(('note:Rubyでできることを増やす'))
|
56
|
+
* Maintain libraries\n
|
57
|
+
(('note:ライブラリーのメンテナンス'))
|
58
|
+
|
59
|
+
= The number of developing libraries\n(('note:開発しているライブラリー数'))
|
60
|
+
|
61
|
+
About 130\n
|
62
|
+
(('note:130くらい'))
|
63
|
+
|
64
|
+
= How to find targets?\n(('note:そんなにネタがあるの?'))
|
65
|
+
|
66
|
+
Just I needed\n
|
67
|
+
(('note:単に自分が必要だったから'))
|
68
|
+
|
69
|
+
= Today's topic\n(('note:今日の話題'))
|
70
|
+
|
71
|
+
Overview\n
|
72
|
+
what we can do\n
|
73
|
+
((*with Ruby*))\n
|
74
|
+
(('note:Rubyでできるようになったことをたくさん紹介'))
|
75
|
+
|
76
|
+
= Category1\n(('note:分類1'))
|
77
|
+
|
78
|
+
Web feed\n
|
79
|
+
(('note:Webフィード'))
|
80
|
+
|
81
|
+
= RSS Parser
|
82
|
+
|
83
|
+
RSS/Atom parser\n
|
84
|
+
with\n
|
85
|
+
((*validation*))\n
|
86
|
+
(('note:バリデーション機能付きのRSS/Atomパーサー'))
|
87
|
+
|
88
|
+
= RSS Parser - History\n(('note:歴史'))
|
89
|
+
|
90
|
+
* 2003-05: The first release\n
|
91
|
+
(('note:最初のリリース'))
|
92
|
+
* No other RSS/Atom parser that supports validation even now\n
|
93
|
+
(('note:今でもバリデーション付きのパーサーは他にない'))
|
94
|
+
* 2004-01: Ruby bundles this\n
|
95
|
+
(('note:RubyがRSS Parserをバンドル'))
|
96
|
+
* I became a Ruby committer\n
|
97
|
+
(('note:Rubyコミッターになる'))
|
98
|
+
|
99
|
+
= Validate RSS/Atom\n(('note:RSS/Atomのバリデーション'))
|
100
|
+
|
101
|
+
* Important for me\n
|
102
|
+
(('note:私にとっては大事'))
|
103
|
+
* Most wild RSS/Atom feeds are\n
|
104
|
+
((*invalid*))\n
|
105
|
+
(('note:野生のRSS/Atomの多くは不正'))
|
106
|
+
* Validation helps to find problems\n
|
107
|
+
(('note:バリデーションがあると問題を見つけやすくなる'))
|
108
|
+
|
109
|
+
= RSS::Parser.parse
|
110
|
+
|
111
|
+
# coderay ruby
|
112
|
+
|
113
|
+
# Validates by default
|
114
|
+
# デフォルトでバリデーション
|
115
|
+
RSS::Parser.parse(rss)
|
116
|
+
# Validation can be disabled
|
117
|
+
# 無効にできる
|
118
|
+
RSS::Parser.parse(rss, false)
|
119
|
+
|
120
|
+
= Since Ruby 2.6\n(('note:Ruby 2.6以降'))
|
121
|
+
|
122
|
+
# coderay ruby
|
123
|
+
|
124
|
+
# Supports keyword argument
|
125
|
+
# キーワード引数対応
|
126
|
+
parse(rss, validate: false)
|
127
|
+
|
128
|
+
= REXML
|
129
|
+
|
130
|
+
XML parser\n
|
131
|
+
written in\n
|
132
|
+
((*pure Ruby*))\n
|
133
|
+
(('note:Ruby実装のXMLパーサー'))
|
134
|
+
|
135
|
+
= REXML - History\n(('note:歴史'))
|
136
|
+
|
137
|
+
* 2001: Started by Sean Russell\n
|
138
|
+
(('note:Seanさんが開発を開始'))
|
139
|
+
* Based on Electric XML (Java)\n
|
140
|
+
(('note:Java実装のElectric XMLを参考に開発'))
|
141
|
+
* REXML is "Ruby Electric XML"\n
|
142
|
+
(('note:REXMLは「Ruby Electric XML」'))
|
143
|
+
* 2003-01: Ruby bundles this\n
|
144
|
+
(('note:RubyがREXMLをバンドル'))
|
145
|
+
|
146
|
+
= REXML - Side story\n(('note:おまけ話'))
|
147
|
+
|
148
|
+
* Sean was "書運" in Kanji\n
|
149
|
+
(('note:Seanさんには「書運」という漢字表記があった'))
|
150
|
+
* He was interested in Japan\n
|
151
|
+
(('note:日本好きだった'))
|
152
|
+
* (('tag:x-small'))"How to write your name in Kanji?"\n
|
153
|
+
(('note:「君の名前は漢字でどう書くの?」'))
|
154
|
+
* We can connect with Ruby!\n
|
155
|
+
(('note:RubyistはRubyをきっかけにつながれる!'))
|
156
|
+
|
157
|
+
= Ad: Code Party\n(('note:宣伝:コード懇親会'))
|
158
|
+
|
159
|
+
# img
|
160
|
+
# src = images/code-party.png
|
161
|
+
# relative_height = 100
|
162
|
+
# reflect_ratio = 0.1
|
163
|
+
|
164
|
+
== Slide properties
|
165
|
+
|
166
|
+
: enable-title-on-image
|
167
|
+
false
|
168
|
+
|
169
|
+
= Ad: Code Party\n(('note:宣伝:コード懇親会'))
|
170
|
+
|
171
|
+
(('tag:center'))
|
172
|
+
This is a challenge\n
|
173
|
+
(('note:実験的な企画'))
|
174
|
+
|
175
|
+
* Ruby focus to have fun\n
|
176
|
+
(('note:Rubyは楽しさを大事にしている'))
|
177
|
+
* We have fun writing Ruby\n
|
178
|
+
(('note:Rubyistは楽しくRubyを書いている'))
|
179
|
+
* We have fun together with writing Ruby at after party!?\n
|
180
|
+
(('note:だったら懇親会で一緒にRubyを書くと楽しそう!?'))
|
181
|
+
|
182
|
+
= Ad: Code Party\n(('note:宣伝:コード懇親会'))
|
183
|
+
|
184
|
+
* Matz attends Code Party\n
|
185
|
+
(('note:まつもとさんもコード懇親会に参加'))
|
186
|
+
* Sponsored by Speee, Inc.\n
|
187
|
+
(('note:Speeeさんがスポンサー'))
|
188
|
+
|
189
|
+
= REXML - Recent1\n(('note:最近1'))
|
190
|
+
|
191
|
+
* 2010-08: RubyKaigi 2010
|
192
|
+
* I became the maintainer\n
|
193
|
+
(('note:私がメンテナーになった'))
|
194
|
+
* Because RSS Parser uses it\n
|
195
|
+
(('note:RSS Parserが使っているから'))
|
196
|
+
|
197
|
+
= REXML - Recent2\n(('note:最近2'))
|
198
|
+
|
199
|
+
* 2016: (({element[attribute_name]}))
|
200
|
+
* Ruby 2.5 ships it\n
|
201
|
+
(('note:Ruby 2.5以降で使える'))
|
202
|
+
|
203
|
+
= REXML - Recent3\n(('note:最近3'))
|
204
|
+
|
205
|
+
* 2018: Fix XPath related bugs\n
|
206
|
+
(('note:XPath関連のバグ修正'))
|
207
|
+
* Ruby 2.6 ships it\n
|
208
|
+
(('note:Ruby 2.6以降で使える'))
|
209
|
+
|
210
|
+
= REXML - Future?\n(('note:未来はあるの?'))
|
211
|
+
|
212
|
+
* ((*Pure Ruby*)) is valuable\n
|
213
|
+
(('note:Rubyだけで書かれていることには価値がある'))
|
214
|
+
* Easy to install\n
|
215
|
+
(('note:インストールが簡単'))
|
216
|
+
* JIT may improve performance\n
|
217
|
+
(('note:NOTE: We should improve general logic before we expect JIT to improve performance😉'))\n
|
218
|
+
(('note:JITで速くなるかもしれない'))\n
|
219
|
+
(('note:JITの前に普通にロジックを改良するのが先だけどね😉'))\n
|
220
|
+
|
221
|
+
= Recent my works\n(('note:最近の仕事'))
|
222
|
+
|
223
|
+
* XML/HTML libraries for LuaJIT\n
|
224
|
+
(('note:LuaJIT用のXML/HTMLライブラリー'))
|
225
|
+
* XMLua: (('tag:xx-small:((<URL:https://clear-code.github.io/xmlua/>))'))\n
|
226
|
+
libxml2 based XML/HTML parser
|
227
|
+
* LuaCS: (('tag:xx-small:((<URL:https://clear-code.github.io/luacs/>))'))\n
|
228
|
+
CSS Selectors→XPath converter
|
229
|
+
* Found what lacks in REXML API\n
|
230
|
+
(('note:REXMLのAPIに足りないものはなにか考えた'))
|
231
|
+
|
232
|
+
= REXML - Future1\n(('note:機能1'))
|
233
|
+
|
234
|
+
Introduce NodeSet\n
|
235
|
+
(('note:NodeSetが足りないんじゃないか'))
|
236
|
+
|
237
|
+
= REXML - NodeSet
|
238
|
+
|
239
|
+
# coderay ruby
|
240
|
+
doc.
|
241
|
+
search("//item"). # => NodeSet
|
242
|
+
text # All texts in <item>
|
243
|
+
|
244
|
+
= REXML - Future2\n(('note:機能2'))
|
245
|
+
|
246
|
+
Support\n
|
247
|
+
CSS Selectors\n
|
248
|
+
(('note:CSSセレクターが足りないんじゃないか'))
|
249
|
+
|
250
|
+
= REXML - CSS Selectors\n(('note:CSSセレクター'))
|
251
|
+
|
252
|
+
# coderay ruby
|
253
|
+
doc.css_select("ul li, dl dt")
|
254
|
+
|
255
|
+
= REXML - Future3\n(('note:機能3'))
|
256
|
+
|
257
|
+
Support\n
|
258
|
+
HTML5 support\n
|
259
|
+
(('note:HTML5対応が足りないんじゃないか'))
|
260
|
+
|
261
|
+
= REXML - HTML5
|
262
|
+
|
263
|
+
# coderay ruby
|
264
|
+
|
265
|
+
doc = REXML::HTML5Document.new(html5)
|
266
|
+
doc.search("//li")
|
267
|
+
doc.css_select("ul li")
|
268
|
+
|
269
|
+
= REXML - Future\n(('note:未来'))
|
270
|
+
|
271
|
+
* Low priority in my activities\n
|
272
|
+
(('note:優先度は高くない'))
|
273
|
+
* Do you want to work with me?\n
|
274
|
+
(('note:一緒にやりたい人はいる?'))
|
275
|
+
|
276
|
+
= Category2\n(('note:分類1'))
|
277
|
+
|
278
|
+
Presentation\n
|
279
|
+
(('note:プレゼンテーション'))
|
280
|
+
|
281
|
+
= Rabbit
|
282
|
+
|
283
|
+
(('tag:center'))
|
284
|
+
(('tag:large'))
|
285
|
+
Presentation tool\n
|
286
|
+
for ((*Rubyist*))\n
|
287
|
+
(('note:Rubyist用のプレゼンツール'))
|
288
|
+
|
289
|
+
((' '))
|
290
|
+
|
291
|
+
= Rabbit - History\n(('note:歴史'))
|
292
|
+
|
293
|
+
* 2004-07: The first release\n
|
294
|
+
(('note:最初のリリース'))
|
295
|
+
* No other presentation tool for Rubyist even now\n
|
296
|
+
(('note:今でもRubyist用のプレゼンツールは他にない'))
|
297
|
+
* 2010: Matz migrated to Rabbit\n
|
298
|
+
(('note:まつもとさんがRabbitに乗り換えた'))
|
299
|
+
* Since RubyKaigi 2010?\n
|
300
|
+
(('note:RubyKaigi 2010から?'))
|
301
|
+
|
302
|
+
= For Rubyist?\n(('note:Rubyist向けに必要なもの'))
|
303
|
+
|
304
|
+
RD support\n
|
305
|
+
(('note:RDサポート'))
|
306
|
+
|
307
|
+
= RD
|
308
|
+
|
309
|
+
* ((*R*))uby ((*D*))ocument\n
|
310
|
+
* Designed by Matz (('note:(Right?)'))\n
|
311
|
+
(('note:まつもとさんがデザインしたはず'))
|
312
|
+
* A text based markup language\n
|
313
|
+
(('note:テキストベースのマークアップ言語'))
|
314
|
+
* Version controllable\n
|
315
|
+
(('note:バージョン管理できる'))
|
316
|
+
|
317
|
+
= For Rubyist?\n(('note:Rubyist向けに必要なもの'))
|
318
|
+
|
319
|
+
Publish\n
|
320
|
+
our slides\n
|
321
|
+
as usual\n
|
322
|
+
(('note:いつも通りスライドを公開できる'))
|
323
|
+
|
324
|
+
= Publish as usual\n(('note:いつも通り公開'))
|
325
|
+
|
326
|
+
# coderay console
|
327
|
+
% gem push your-slide-1.0.gem
|
328
|
+
|
329
|
+
= Published!\n(('note:公開完了!'))
|
330
|
+
|
331
|
+
# img
|
332
|
+
# src = images/rabbit-slide-show.png
|
333
|
+
# relative_height = 78
|
334
|
+
|
335
|
+
(('tag:center'))
|
336
|
+
(('tag:small'))
|
337
|
+
((<URL:https://slide.rabbit-shocker.org/>))
|
338
|
+
|
339
|
+
= What's needed for presentation tool?\n(('note:プレゼンツールに必要なもの'))
|
340
|
+
|
341
|
+
GUI
|
342
|
+
|
343
|
+
= Ruby/GTK3
|
344
|
+
|
345
|
+
Multi-platform GUI toolkit\n
|
346
|
+
(('note:複数プラットフォーム対応GUIツールキット'))
|
347
|
+
|
348
|
+
= Ruby/GTK3 - History\n(('note:歴史'))
|
349
|
+
|
350
|
+
* 1998-01: 1st release by Matz\n
|
351
|
+
((<[ruby-list:5877]|URL:http://blade.nagaokaut.ac.jp/cgi-bin/scat.rb/ruby/ruby-list/5877>))\n
|
352
|
+
(('note:まつもとさんが最初のリリース'))
|
353
|
+
* 2004-05: I joined development\n
|
354
|
+
(('note:私が開発に参加'))
|
355
|
+
|
356
|
+
= Example - Window
|
357
|
+
|
358
|
+
# coderay ruby
|
359
|
+
require "gtk3"
|
360
|
+
app = Gtk::Application.new
|
361
|
+
app.signal_connect(:activate) do
|
362
|
+
window = Gtk::ApplicationWindow.new(app)
|
363
|
+
window.show_all
|
364
|
+
end
|
365
|
+
app.run
|
366
|
+
|
367
|
+
= Approaches on\nmissing libraries(1)\n(('note:ライブラリーがない時のやり方(1)'))
|
368
|
+
|
369
|
+
(1) Implement only the needed features\n
|
370
|
+
(('note:必要な機能だけ実装'))
|
371
|
+
(2) then back to Rabbit\n
|
372
|
+
(('note:必要な機能ができたらRabbitに戻る'))
|
373
|
+
|
374
|
+
= Approaches on\nmissing libraries(2)\n(('note:ライブラリーがない時のやり方(2)'))
|
375
|
+
|
376
|
+
(1) Implement not only the needed features\n
|
377
|
+
(('note:必要な機能だけじゃなく'))
|
378
|
+
(2) but also (('note:almost')) all features\n
|
379
|
+
(('note:ほぼすべての機能を実装'))
|
380
|
+
(3) then back to Rabbit\n
|
381
|
+
(('note:終わったらRabbitに戻る'))
|
382
|
+
|
383
|
+
= My approach\n(('note:私のやり方'))
|
384
|
+
|
385
|
+
Implement\n
|
386
|
+
all features\n
|
387
|
+
(('note:testing with Rabbit'))\n
|
388
|
+
(('note:すべての機能を実装'))
|
389
|
+
|
390
|
+
= My priority\n(('note:私の優先度'))
|
391
|
+
|
392
|
+
* Rabbit is important\n
|
393
|
+
(('note:Rabbitは大事だけど'))
|
394
|
+
* Increasing what Ruby can is also important\n
|
395
|
+
(('note:Rubyでできることを増やすのも大事'))
|
396
|
+
|
397
|
+
= GTK+ 3 - Size\n(('note:サイズ'))
|
398
|
+
|
399
|
+
3000 over API\n
|
400
|
+
(('note:3000以上のAPI'))
|
401
|
+
|
402
|
+
= How to implement\n(('note:実装方法'))
|
403
|
+
|
404
|
+
Handwriting\n
|
405
|
+
(('note:手書き'))\n
|
406
|
+
↓\n
|
407
|
+
Auto generation\n
|
408
|
+
(('note:自動生成'))
|
409
|
+
|
410
|
+
= Ruby/GI
|
411
|
+
|
412
|
+
(('tag:center'))
|
413
|
+
(('tag:large'))
|
414
|
+
Generate bindings\n
|
415
|
+
automatically\n
|
416
|
+
at run-time\n
|
417
|
+
(('note:実行時に自動でバインディングを生成'))
|
418
|
+
|
419
|
+
(('note:GI: GObject Introspection'))
|
420
|
+
|
421
|
+
= Ruby/GI - History\n(('note:歴史'))
|
422
|
+
|
423
|
+
* 2012: The first commit by me\n
|
424
|
+
(('note:最初のコミット'))
|
425
|
+
* 2014: Ruby/GTK3 used Ruby/GI\n
|
426
|
+
(('note:Ruby/GTK3をRuby/GIベースに移行'))
|
427
|
+
|
428
|
+
= Handwriting\n(('note:手書き'))
|
429
|
+
|
430
|
+
# img
|
431
|
+
# src = images/ruby-gtk3-without-ruby-gi.svg
|
432
|
+
# relative_width = 100
|
433
|
+
|
434
|
+
== Slide properties
|
435
|
+
|
436
|
+
: enable-title-on-image
|
437
|
+
false
|
438
|
+
|
439
|
+
= Auto generation\n(('note:自動生成'))
|
440
|
+
|
441
|
+
# img
|
442
|
+
# src = images/ruby-gtk3-with-ruby-gi.svg
|
443
|
+
# relative_width = 100
|
444
|
+
|
445
|
+
== Slide properties
|
446
|
+
|
447
|
+
: enable-title-on-image
|
448
|
+
false
|
449
|
+
|
450
|
+
= Ruby/GI - See also\n(('note:参考情報'))
|
451
|
+
|
452
|
+
* "How to create bindings 2016" at RubyKaigi 2016\n
|
453
|
+
* (('tag:xx-small'))
|
454
|
+
((<URL:http://rubykaigi.org/2016/presentations/ktou.html>))
|
455
|
+
* "GI Introduction" (('note:(in Japanese)'))\n
|
456
|
+
(('note:「GObject Introspection入門」'))
|
457
|
+
* (('tag:xx-small'))
|
458
|
+
((<URL:https://github.com/RubyData/workshop-materials/blob/master/gobject-introspection/introduction.md>))
|
459
|
+
* Build system: Meson + Ninja\n
|
460
|
+
(('note:ビルドシステム:Meson + Ninja'))
|
461
|
+
|
462
|
+
= Ruby/GI based bindings\n(('note:Ruby/GIベースのバインディング'))
|
463
|
+
|
464
|
+
Ruby/Pango
|
465
|
+
|
466
|
+
= Ruby/Pango
|
467
|
+
|
468
|
+
(('tag:center'))
|
469
|
+
(('tag:large'))
|
470
|
+
Text layout engine\n
|
471
|
+
with\n
|
472
|
+
i18n support\n
|
473
|
+
(('note:国際化対応のテキストレイアウトエンジン'))
|
474
|
+
|
475
|
+
(('note:i18n: Internationalization'))
|
476
|
+
|
477
|
+
= Prohibition processing\n(('note:禁則処理'))
|
478
|
+
|
479
|
+
# coderay ruby
|
480
|
+
|
481
|
+
widget.signal_connect(:draw) do |_, context|
|
482
|
+
layout = context.create_pango_layout
|
483
|
+
layout.text = "Helloこんにちは。🍣"
|
484
|
+
context.show_pango_layout(layout)
|
485
|
+
GLib::Source::CONTINUE
|
486
|
+
end
|
487
|
+
|
488
|
+
= Bidirectional text\n(('note:双方向テキスト'))
|
489
|
+
|
490
|
+
Hello
|
491
|
+
|
492
|
+
مرحبا
|
493
|
+
|
494
|
+
こんにちは
|
495
|
+
|
496
|
+
= Ruby/GI based bindings\n(('note:Ruby/GIベースのバインディング'))
|
497
|
+
|
498
|
+
Ruby/GdkPixbuf2
|
499
|
+
|
500
|
+
= Ruby/GdkPixbuf2
|
501
|
+
|
502
|
+
Image manipulation\n
|
503
|
+
(('note:画像操作'))
|
504
|
+
|
505
|
+
= Half image\n(('note:画像を半分に'))
|
506
|
+
|
507
|
+
# coderay ruby
|
508
|
+
|
509
|
+
require "gdk_pixbuf2"
|
510
|
+
# Load an image: Format is auto detected
|
511
|
+
pixbuf = GdkPixbuf::Pixbuf.new(file: "x.png")
|
512
|
+
# Scale to half size
|
513
|
+
half = pixbuf.scale(pixbuf.width / 2,
|
514
|
+
pixbuf.height / 2,
|
515
|
+
:bilinear)
|
516
|
+
# Save as different format
|
517
|
+
half.save("half.jpg")
|
518
|
+
|
519
|
+
= Animation GIF\n(('note:アニメーションGIF'))
|
520
|
+
|
521
|
+
# img
|
522
|
+
# src = images/the-tortoise-and-the-hare.gif
|
523
|
+
# relative_width = 100
|
524
|
+
|
525
|
+
== Slide properties
|
526
|
+
|
527
|
+
: enable-title-on-image
|
528
|
+
false
|
529
|
+
|
530
|
+
= Ruby/GI based bindings\n(('note:Ruby/GIベースのバインディング'))
|
531
|
+
|
532
|
+
Ruby/Poppler
|
533
|
+
|
534
|
+
= Ruby/Poppler
|
535
|
+
|
536
|
+
PDF\n
|
537
|
+
parser/renderer\n
|
538
|
+
(('note:PDFパーサー・レンダラー'))
|
539
|
+
|
540
|
+
= Text extraction\n(('note:テキスト抽出'))
|
541
|
+
|
542
|
+
# coderay ruby
|
543
|
+
|
544
|
+
require "poppler"
|
545
|
+
doc = Poppler::Document.new("x.pdf")
|
546
|
+
doc.each do |page|
|
547
|
+
puts(page.text) # Extract all texts
|
548
|
+
end
|
549
|
+
|
550
|
+
= Embed PDF\n(('note:PDFの埋め込み'))
|
551
|
+
|
552
|
+
# image
|
553
|
+
# src = images/rubykaigi-2017-extension-by-cpp-title.pdf
|
554
|
+
# relative_height = 80
|
555
|
+
# reflect_ratio = 0.1
|
556
|
+
|
557
|
+
(('tag:center'))
|
558
|
+
(('tag:xx-small'))
|
559
|
+
((<URL:http://rubykaigi.org/2017/presentations/ktou.html>))
|
560
|
+
|
561
|
+
== Slide properties
|
562
|
+
|
563
|
+
: enable-title-on-image
|
564
|
+
false
|
565
|
+
|
566
|
+
= Ruby/GI based bindings\n(('note:Ruby/GIベースのバインディング'))
|
567
|
+
|
568
|
+
Ruby/GStreamer
|
569
|
+
|
570
|
+
= Ruby/GStreamer
|
571
|
+
|
572
|
+
(('tag:center'))
|
573
|
+
(('tag:large'))
|
574
|
+
Audio/Video player\n
|
575
|
+
(('note:音声・動画プレイヤー'))
|
576
|
+
|
577
|
+
(('note:(*) Streaming media framework'))\n
|
578
|
+
(('note:本当はストリーミングメディアフレームワーク'))
|
579
|
+
|
580
|
+
= Camera(('note:(カメラ)'))
|
581
|
+
|
582
|
+
# coderay ruby
|
583
|
+
|
584
|
+
require "gst"
|
585
|
+
description = [
|
586
|
+
"autovideosrc", # Camera
|
587
|
+
"videoconvert", # Filter
|
588
|
+
"autovideosink", # Window
|
589
|
+
].join(" ! ")
|
590
|
+
pipeline = Gst.parse_launch(description)
|
591
|
+
pipeline.play
|
592
|
+
until pipeline.bus.poll.type.eos? do
|
593
|
+
end # Main loop
|
594
|
+
pipeline.stop
|
595
|
+
|
596
|
+
= Face detection\n(('note:顔認識'))
|
597
|
+
|
598
|
+
# coderay ruby
|
599
|
+
|
600
|
+
description = [
|
601
|
+
"autovideosrc", # Camera
|
602
|
+
"videoconvert", # Filter
|
603
|
+
"facedetect", # Face detection (!)
|
604
|
+
"videoconvert", # Filter (!)
|
605
|
+
"autovideosink", # Window
|
606
|
+
].join(" ! ")
|
607
|
+
pipeline = Gst.parse_launch(description)
|
608
|
+
pipeline.play
|
609
|
+
|
610
|
+
# = Embed video
|
611
|
+
|
612
|
+
# TODO
|
613
|
+
|
614
|
+
# # # video
|
615
|
+
# # # src = test.mp4
|
616
|
+
|
617
|
+
= What's needed for presentation tool?\n(('note:プレゼンツールに必要なもの'))
|
618
|
+
|
619
|
+
PDF output\n
|
620
|
+
(('note:PDF出力'))
|
621
|
+
|
622
|
+
= rcairo
|
623
|
+
|
624
|
+
2D graphics renderer\n
|
625
|
+
(('note:2次元画像レンダラー'))
|
626
|
+
|
627
|
+
= rcairo - Outputs\n(('note:出力'))
|
628
|
+
|
629
|
+
* PNG・SVG
|
630
|
+
* ((*PDF*))
|
631
|
+
* ((*Display*)) (X/macOS/Windows)
|
632
|
+
* ...
|
633
|
+
|
634
|
+
= rcairo - History\n(('note:歴史'))
|
635
|
+
|
636
|
+
* 2003-10: The initial commit\n
|
637
|
+
(('note:最初のコミット'))
|
638
|
+
* 2005-09: I started developing\n
|
639
|
+
(('note:私が開発に参加'))
|
640
|
+
|
641
|
+
= Red A4 PDF\n(('note:赤いA4のPDFを出力'))
|
642
|
+
|
643
|
+
# coderay ruby
|
644
|
+
|
645
|
+
require "cairo"
|
646
|
+
include Cairo
|
647
|
+
PDFSurface.create("x.pdf", "A4") do |surface|
|
648
|
+
Context.create(surface) do |context|
|
649
|
+
context.set_source_color(:red)
|
650
|
+
context.paint
|
651
|
+
end
|
652
|
+
end
|
653
|
+
|
654
|
+
= rcairo - GC
|
655
|
+
|
656
|
+
# image
|
657
|
+
# src = images/cairo-no-gc-trigger.pdf
|
658
|
+
# align = right
|
659
|
+
# vertical_align = bottom
|
660
|
+
# relative_width = 65
|
661
|
+
# relative_padding_right = -7
|
662
|
+
# relative_padding_bottom = -10
|
663
|
+
|
664
|
+
# coderay ruby
|
665
|
+
1000.times do
|
666
|
+
Cairo::ImageSurface.new(:argb32, 6000, 6000)
|
667
|
+
end
|
668
|
+
|
669
|
+
(('tag:margin-bottom * 20'))
|
670
|
+
|
671
|
+
= GC - Cause(('note:(原因)'))
|
672
|
+
|
673
|
+
# image
|
674
|
+
# src = images/cairo-no-gc-trigger.pdf
|
675
|
+
# align = right
|
676
|
+
# vertical_align = bottom
|
677
|
+
# relative_width = 67
|
678
|
+
# relative_padding_right = -11
|
679
|
+
# relative_padding_bottom = -10
|
680
|
+
|
681
|
+
* GC isn't ran enough frequency\n
|
682
|
+
(('note:GCの実行頻度が十分じゃなかった'))
|
683
|
+
* Because Ruby doesn't know how many memory used by cairo\n
|
684
|
+
(('note:Rubyはcairoのメモリー使用量を知らないから'))
|
685
|
+
|
686
|
+
(('tag:margin-bottom * 16'))
|
687
|
+
|
688
|
+
= GC - Fix(('note:(修正)'))
|
689
|
+
|
690
|
+
# image
|
691
|
+
# src = images/cairo-gc-trigger.pdf
|
692
|
+
# align = right
|
693
|
+
# vertical_align = bottom
|
694
|
+
# relative_width = 67
|
695
|
+
# relative_padding_right = -11
|
696
|
+
# relative_padding_bottom = -10
|
697
|
+
|
698
|
+
* (({rb_gc_adjust_memory_usage()}))
|
699
|
+
* Improve GC frequency(('note:(GC実行頻度を改善)'))
|
700
|
+
* Ruby 2.4 ships it(('note:(Ruby 2.4以降)'))
|
701
|
+
|
702
|
+
(('tag:margin-bottom * 18'))
|
703
|
+
|
704
|
+
= Easy to install\n(('note:簡単インストール'))
|
705
|
+
|
706
|
+
Important\n
|
707
|
+
(('note:大事'))
|
708
|
+
|
709
|
+
= native-package-installer
|
710
|
+
|
711
|
+
Install\n
|
712
|
+
system packages\n
|
713
|
+
on (({gem install}))\n
|
714
|
+
(('note:gem install時にシステムのパッケージをインストール'))
|
715
|
+
|
716
|
+
= extconf.rb/Rakefile
|
717
|
+
|
718
|
+
# coderay ruby
|
719
|
+
|
720
|
+
require "pkg-config"
|
721
|
+
require "native-package-installer"
|
722
|
+
unless PKGConfig.check_version?("gdk-3.0")
|
723
|
+
packages = {
|
724
|
+
altlinux: "libgtk+3-devel",
|
725
|
+
debian: "libgtk-3-dev",
|
726
|
+
redhat: "pkgconfig(gdk-3.0)",
|
727
|
+
homebrew: "gtk+3",
|
728
|
+
macports: "gtk3",
|
729
|
+
msys2: "gtk3",
|
730
|
+
}
|
731
|
+
unless NativePackageInstaller.install(packages)
|
732
|
+
exit(false)
|
733
|
+
end
|
734
|
+
end
|
735
|
+
|
736
|
+
= rake-compiler
|
737
|
+
|
738
|
+
Build fat gem\n
|
739
|
+
by\n
|
740
|
+
cross compile\n
|
741
|
+
(('note:クロスコンパイルでfat gemをビルド'))
|
742
|
+
|
743
|
+
= rake-compiler - History\n(('note:歴史'))
|
744
|
+
|
745
|
+
* 2008-11: The first commit\n
|
746
|
+
(('note:最初のコミット'))
|
747
|
+
* 2014-12: Orphan\n
|
748
|
+
(('note:だれかメンテナー変わってー'))
|
749
|
+
* 2014-12:\n
|
750
|
+
I became the maintainer\n
|
751
|
+
(('note:私がメンテナーになった'))
|
752
|
+
|
753
|
+
= Category3\n(('note:分類3'))
|
754
|
+
|
755
|
+
Test\n
|
756
|
+
(('note:テスト'))
|
757
|
+
|
758
|
+
= test-unit
|
759
|
+
|
760
|
+
Testing framework\n
|
761
|
+
to write tests\n
|
762
|
+
((*in Ruby*))\n
|
763
|
+
(('note:Rubyでテストを書けるテスティングフレームワーク'))
|
764
|
+
|
765
|
+
= test-unit - History\n(('note:歴史'))
|
766
|
+
|
767
|
+
* 2003-02: Import to Ruby\n
|
768
|
+
(('note:Rubyに取り込まれる'))
|
769
|
+
* 2008-05:\n
|
770
|
+
I became the maintainer\n
|
771
|
+
(('note:私がメンテナーになった'))
|
772
|
+
* 2008-10: Removed from Ruby\n
|
773
|
+
(('note:Rubyから削除'))
|
774
|
+
|
775
|
+
(('note:See also: "The history of testing framework in Ruby"'))\n
|
776
|
+
(('tag:x-small'))((<URL:http://rubykaigi.org/2015/presentations/kou>))
|
777
|
+
|
778
|
+
= test-unit - New feature\n(('note:新機能'))
|
779
|
+
|
780
|
+
Grouping\n
|
781
|
+
(('note:グループ化'))
|
782
|
+
|
783
|
+
= Grouping\n(('note:グループ化'))
|
784
|
+
|
785
|
+
* The most important feature\n
|
786
|
+
(('note:一番大事な機能'))
|
787
|
+
* Keep tests maintainable\n
|
788
|
+
(('note:メンテナンスできるテストを維持できる'))
|
789
|
+
|
790
|
+
= Example(('note:(例)'))
|
791
|
+
|
792
|
+
# coderay ruby
|
793
|
+
|
794
|
+
class StackTest < Test::Unit::TestCase
|
795
|
+
class PushTest < self
|
796
|
+
def test_XXX; end
|
797
|
+
end
|
798
|
+
class PopTest < self
|
799
|
+
def test_XXX; end
|
800
|
+
end
|
801
|
+
end
|
802
|
+
|
803
|
+
= Method style(('note:(メソッド形式)'))
|
804
|
+
|
805
|
+
# coderay ruby
|
806
|
+
|
807
|
+
class StackTest < Test::Unit::TestCase
|
808
|
+
sub_test_case("#push") do
|
809
|
+
def test_XXX; end
|
810
|
+
end
|
811
|
+
sub_test_case("#pop") do
|
812
|
+
def test_XXX; end
|
813
|
+
end
|
814
|
+
end
|
815
|
+
|
816
|
+
= test-unit - New feature\n(('note:新機能'))
|
817
|
+
|
818
|
+
Data driven test\n
|
819
|
+
(('note:データ駆動テスト'))
|
820
|
+
|
821
|
+
= Data driven test\n(('note:データ駆動テスト'))
|
822
|
+
|
823
|
+
# coderay ruby
|
824
|
+
|
825
|
+
data("positive", [3, 1, 2])
|
826
|
+
data("negative", [-4, 1, -5])
|
827
|
+
def test_add(data)
|
828
|
+
expected, augend, addend = data
|
829
|
+
assert_equal(expected,
|
830
|
+
add(augend, addend))
|
831
|
+
end
|
832
|
+
|
833
|
+
= test-unit - New feature\n(('note:新機能'))
|
834
|
+
|
835
|
+
Reverse backtrace\n
|
836
|
+
(('note:逆順のバックトレース'))
|
837
|
+
|
838
|
+
= Reverse backtrace\n(('note:逆順のバックトレース'))
|
839
|
+
|
840
|
+
* Reverse backtrace only when terminal output\n
|
841
|
+
(('note:ターミナル出力のときだけ逆順'))
|
842
|
+
* The same change as Ruby 2.5.0\n
|
843
|
+
(('note:Ruby 2.5.0と同じ変更'))
|
844
|
+
|
845
|
+
= test-unit - New feature\n(('note:新機能'))
|
846
|
+
|
847
|
+
Test double\n
|
848
|
+
(('note:テストダブル'))
|
849
|
+
|
850
|
+
= test-unit-rr
|
851
|
+
|
852
|
+
RR integration\n
|
853
|
+
(('note:RRとの統合'))
|
854
|
+
|
855
|
+
= RR - History\n(('note:歴史'))
|
856
|
+
|
857
|
+
* 2007-06: The initial commit\n
|
858
|
+
(('note:最初のコミット'))
|
859
|
+
* 2014-12: Orphan\n
|
860
|
+
(('note:だれかメンテナー変わってー'))
|
861
|
+
* 2015-05:\n
|
862
|
+
I became the maintainer\n
|
863
|
+
(('note:私がメンテナーになった'))
|
864
|
+
|
865
|
+
= Stub(('note:(スタブ)'))
|
866
|
+
|
867
|
+
# coderay ruby
|
868
|
+
|
869
|
+
adder = Object.new
|
870
|
+
adder.add(1, 2) # => Error
|
871
|
+
stub(adder).add(1, 2) {3}
|
872
|
+
adder.add(1, 2) # => 3
|
873
|
+
|
874
|
+
= Category4\n(('note:分類4'))
|
875
|
+
|
876
|
+
Full text search\n
|
877
|
+
(('note:全文検索'))
|
878
|
+
|
879
|
+
= Rroonga
|
880
|
+
|
881
|
+
Full text search\n
|
882
|
+
((*library*))\n
|
883
|
+
(('note:全文検索ライブラリー'))
|
884
|
+
|
885
|
+
= ((*Library*)) vs Client\n(('note:ライブラリー対クライアント'))
|
886
|
+
|
887
|
+
* No server process\n
|
888
|
+
(('note:サーバープロセスがいらない'))
|
889
|
+
* Easy to start\n
|
890
|
+
(('note:簡単に使い始められる'))
|
891
|
+
* Write in Ruby\n
|
892
|
+
(('note:Rubyで書ける'))
|
893
|
+
|
894
|
+
= Create DB(('note:(データベース作成)'))
|
895
|
+
|
896
|
+
# coderay ruby
|
897
|
+
require "groonga"
|
898
|
+
|
899
|
+
Groonga::Database.create(path: "/tmp/db")
|
900
|
+
|
901
|
+
= Define schema(('note:(スキーマ定義)'))
|
902
|
+
|
903
|
+
# coderay ruby
|
904
|
+
|
905
|
+
Groonga::Schema.define do |schema|
|
906
|
+
schema.create_table("docs") do |table|
|
907
|
+
# The column to store text
|
908
|
+
table.text("content")
|
909
|
+
end
|
910
|
+
# The index for full text search
|
911
|
+
schema.create_lexicon("terms") do |table|
|
912
|
+
table.index("docs.content")
|
913
|
+
end
|
914
|
+
end
|
915
|
+
|
916
|
+
= Add records(('note:(レコード追加)'))
|
917
|
+
|
918
|
+
# coderay ruby
|
919
|
+
|
920
|
+
docs = Groonga["docs"]
|
921
|
+
docs.add(content: "String#<< concatenates ...")
|
922
|
+
docs.add(content: "String#dup duplicates ...")
|
923
|
+
|
924
|
+
= Search(('note:(検索)'))
|
925
|
+
|
926
|
+
# coderay ruby
|
927
|
+
|
928
|
+
matches = docs.select do |record|
|
929
|
+
record.content.match("concat")
|
930
|
+
end
|
931
|
+
p matches.size # => 1
|
932
|
+
matches.each do |record|
|
933
|
+
p record.content # => "String#<< concat..."
|
934
|
+
end
|
935
|
+
|
936
|
+
= User - Rabbit Slide Show
|
937
|
+
|
938
|
+
# img
|
939
|
+
# src = images/rabbit-slide-show.png
|
940
|
+
# relative_height = 78
|
941
|
+
|
942
|
+
(('tag:center'))
|
943
|
+
(('tag:small'))
|
944
|
+
((<URL:https://slide.rabbit-shocker.org/>))
|
945
|
+
|
946
|
+
= User - Rurema Search
|
947
|
+
|
948
|
+
# img
|
949
|
+
# src = images/rurema-search.png
|
950
|
+
# relative_height = 78
|
951
|
+
|
952
|
+
(('tag:center'))
|
953
|
+
(('tag:small'))
|
954
|
+
((<URL:https://docs.ruby-lang.org/ja/search/>))
|
955
|
+
|
956
|
+
= Rurema Search\n(('note:るりまサーチ'))
|
957
|
+
|
958
|
+
* Super fast!\n
|
959
|
+
(('note:すごく速い!'))
|
960
|
+
* Tune for programming document\n
|
961
|
+
(('note:プログラミングのドキュメント用にチューニング'))
|
962
|
+
* Symbols (@, #, ...) are important\n
|
963
|
+
(('note:@とか#とかの記号も大事'))
|
964
|
+
|
965
|
+
= User - RDoc Search
|
966
|
+
|
967
|
+
* Planning\n
|
968
|
+
(('note:考えてはいるけど。。。'))
|
969
|
+
* Do you want to work with me?\n
|
970
|
+
(('note:一緒にやりたい人はいる?'))
|
971
|
+
|
972
|
+
= Rurema and RDoc
|
973
|
+
|
974
|
+
# RT
|
975
|
+
|
976
|
+
Project, Language, Target
|
977
|
+
|
978
|
+
Rurema, Japanese, Japanese Rubyists
|
979
|
+
RDoc, English, All Rubyists
|
980
|
+
|
981
|
+
= Source\n(('note:ソース'))
|
982
|
+
|
983
|
+
* Shared nothing\n
|
984
|
+
(('note:共有していない'))
|
985
|
+
* Copy based share\n
|
986
|
+
(('note:共有するときはコピー'))
|
987
|
+
* e.g.:\n
|
988
|
+
Description,\n
|
989
|
+
Sample codes,\n
|
990
|
+
...\n
|
991
|
+
(('note:例:説明やサンプルコードなどをコピー'))
|
992
|
+
|
993
|
+
= From my point of view\n(('note:私が思うこと'))
|
994
|
+
|
995
|
+
* Can we share documents?\n
|
996
|
+
(('note:ドキュメントを共有できないかな'))
|
997
|
+
* How to work together deeply?\n
|
998
|
+
(('note:もっと協力してできないかな'))
|
999
|
+
|
1000
|
+
= I18n\n(('note:国際化'))
|
1001
|
+
|
1002
|
+
* Source: RDoc\n
|
1003
|
+
(('note:ソースはRDoc'))
|
1004
|
+
* For all Rubyists\n
|
1005
|
+
(('note:これは全Rubyist向け'))
|
1006
|
+
* Translate to Japanese\n
|
1007
|
+
(('note:RDocのドキュメントを日本語に翻訳'))
|
1008
|
+
* For Japanese Rubyists\n
|
1009
|
+
(('note:これは日本人Rubyist向け'))
|
1010
|
+
|
1011
|
+
= Add i18n support\n(('note:国際化サポートを追加'))
|
1012
|
+
|
1013
|
+
* YARD
|
1014
|
+
* Since 0.8.0 at 2012-04
|
1015
|
+
* RDoc
|
1016
|
+
* Since 4.2.0 at 2014-12
|
1017
|
+
|
1018
|
+
= YARD - i18n
|
1019
|
+
|
1020
|
+
# coderay console
|
1021
|
+
|
1022
|
+
# Generates po/yard.pot
|
1023
|
+
# po/yard.potを生成
|
1024
|
+
% yard i18n
|
1025
|
+
|
1026
|
+
= YARD - i18n
|
1027
|
+
|
1028
|
+
# coderay console
|
1029
|
+
|
1030
|
+
# Create po/ja.po from po/yard.pot
|
1031
|
+
# po/yard.potからpo/ja.poを作成
|
1032
|
+
% msginit \
|
1033
|
+
--locale=ja_JP.UTF-8 \
|
1034
|
+
--input=po/yard.pot \
|
1035
|
+
--output-file=po/ja.po
|
1036
|
+
|
1037
|
+
= YARD - i18n
|
1038
|
+
|
1039
|
+
# coderay console
|
1040
|
+
|
1041
|
+
# Translate messages in po/ja.po
|
1042
|
+
# po/ja.po内のメッセージを翻訳
|
1043
|
+
% editor po/ja.po
|
1044
|
+
|
1045
|
+
= YARD - i18n
|
1046
|
+
|
1047
|
+
# coderay console
|
1048
|
+
|
1049
|
+
# Generate documents with
|
1050
|
+
# translated messages
|
1051
|
+
# 翻訳したメッセージを使って
|
1052
|
+
# ドキュメント生成
|
1053
|
+
% yard --locale ja
|
1054
|
+
|
1055
|
+
= Packnga
|
1056
|
+
|
1057
|
+
Rake task\n
|
1058
|
+
for\n
|
1059
|
+
YARD i18n\n
|
1060
|
+
(('note:YARDの国際化機能向けのRakeタスク'))
|
1061
|
+
|
1062
|
+
= Setting\n(('note:設定'))
|
1063
|
+
|
1064
|
+
# coderay ruby
|
1065
|
+
|
1066
|
+
# Rakefile
|
1067
|
+
require "packnga"
|
1068
|
+
Packnga::DocumentTask.new(spec) do |task|
|
1069
|
+
task.original_language = "en"
|
1070
|
+
task.translate_languages = ["ja"]
|
1071
|
+
end
|
1072
|
+
|
1073
|
+
= Workflow\n(('note:ワークフロー'))
|
1074
|
+
|
1075
|
+
# coderay console
|
1076
|
+
|
1077
|
+
% rake reference:translate
|
1078
|
+
% editor doc/po/ja/x.edit.po
|
1079
|
+
% rake reference:translate
|
1080
|
+
% editor lib/x.rb
|
1081
|
+
% rake reference:translate
|
1082
|
+
...
|
1083
|
+
|
1084
|
+
= Users\n(('note:ユーザー'))
|
1085
|
+
|
1086
|
+
* test-unit
|
1087
|
+
* Rroonga
|
1088
|
+
* ...
|
1089
|
+
|
1090
|
+
= RDoc - i18n
|
1091
|
+
|
1092
|
+
# coderay console
|
1093
|
+
|
1094
|
+
# Generates doc/rdoc.pot
|
1095
|
+
# doc/rdoc.potを生成
|
1096
|
+
% rdoc --format=pot
|
1097
|
+
|
1098
|
+
= RDoc - i18n
|
1099
|
+
|
1100
|
+
# coderay console
|
1101
|
+
|
1102
|
+
# Create locale/ja.po
|
1103
|
+
# from doc/rdoc.pot
|
1104
|
+
# doc/rdoc.potからlocale/ja.poを作成
|
1105
|
+
% mkdir -p locale
|
1106
|
+
% msginit \
|
1107
|
+
--locale=ja_JP.UTF-8 \
|
1108
|
+
--input=doc/rdoc.pot \
|
1109
|
+
--output-file=locale/ja.po
|
1110
|
+
|
1111
|
+
= RDoc - i18n
|
1112
|
+
|
1113
|
+
# coderay console
|
1114
|
+
|
1115
|
+
# Translate messages in locale/ja.po
|
1116
|
+
# locale/ja.po内のメッセージを翻訳
|
1117
|
+
% editor locale/ja.po
|
1118
|
+
|
1119
|
+
= RDoc - i18n
|
1120
|
+
|
1121
|
+
# coderay console
|
1122
|
+
|
1123
|
+
# Generate documents with
|
1124
|
+
# translated messages
|
1125
|
+
# 翻訳したメッセージを使って
|
1126
|
+
# ドキュメント生成
|
1127
|
+
% rdoc --locale ja
|
1128
|
+
|
1129
|
+
= RDoc, Rurema and i18n
|
1130
|
+
|
1131
|
+
* No progress...\n
|
1132
|
+
(('note:ツールの整備まででそれ以降は進んでいない。。。'))
|
1133
|
+
* Do you want to work with me?\n
|
1134
|
+
(('note:一緒にやりたい人はいる?'))
|
1135
|
+
|
1136
|
+
= jekyll-task-i18n
|
1137
|
+
|
1138
|
+
Jekyll + i18n
|
1139
|
+
|
1140
|
+
= Features\n(('note:機能'))
|
1141
|
+
|
1142
|
+
* Support all markups!\n
|
1143
|
+
(('note:すべてのマークアップ対応!'))
|
1144
|
+
* GitHub Pages ready!\n
|
1145
|
+
(('note:GitHub Pagesでも使える!'))
|
1146
|
+
|
1147
|
+
= Setting(('note:(設定)'))
|
1148
|
+
|
1149
|
+
# coderay ruby
|
1150
|
+
|
1151
|
+
# Rakefile
|
1152
|
+
require "jekyll/task/i18n"
|
1153
|
+
Jekyll::Task::I18n.define do |task|
|
1154
|
+
task.locales = ["ja"]
|
1155
|
+
task.files = Rake::FileList["**/*.md"]
|
1156
|
+
task.files -= Rake::FileList["_*/**/*.md"]
|
1157
|
+
task.locales.each do |locale|
|
1158
|
+
task.files -= Rake::FileList["#{locale}/**/*.md"]
|
1159
|
+
end
|
1160
|
+
end
|
1161
|
+
task default: ["jekyll:i18n:translate"]
|
1162
|
+
|
1163
|
+
= Workflow(('note:(ワークフロー)'))
|
1164
|
+
|
1165
|
+
% editor index.md
|
1166
|
+
% rake
|
1167
|
+
% editor _po/ja/index.edit.po
|
1168
|
+
% rake
|
1169
|
+
% git commit -a
|
1170
|
+
|
1171
|
+
= User - Red Data Tools
|
1172
|
+
|
1173
|
+
# img
|
1174
|
+
# src = images/jekyll-task-i18n-red-data-tools.gif
|
1175
|
+
# relative_height = 78
|
1176
|
+
|
1177
|
+
(('tag:center'))
|
1178
|
+
(('tag:small'))
|
1179
|
+
((<URL:https://red-data-tools.github.io/>))
|
1180
|
+
|
1181
|
+
= groonga-client
|
1182
|
+
|
1183
|
+
Full text search\n
|
1184
|
+
((*client*))\n
|
1185
|
+
(('note:全文検索クライアント'))
|
1186
|
+
|
1187
|
+
= Library vs ((*Client*))\n(('note:ライブラリー対クライアント'))
|
1188
|
+
|
1189
|
+
* Less dependencies\n
|
1190
|
+
(('note:依存関係が少ない'))
|
1191
|
+
* Less needed resource\n
|
1192
|
+
(('note:必要なリソースが少ない'))
|
1193
|
+
|
1194
|
+
= Search(('note:(検索)'))
|
1195
|
+
|
1196
|
+
# coderay ruby
|
1197
|
+
|
1198
|
+
require "groonga/client"
|
1199
|
+
url = "http://localhost:10041"
|
1200
|
+
Groonga::Client.open(url: url) do |client|
|
1201
|
+
response =
|
1202
|
+
client.select(table: "docs",
|
1203
|
+
match_columns: "content",
|
1204
|
+
query: "concat")
|
1205
|
+
p response.n_hits # => 1
|
1206
|
+
end
|
1207
|
+
|
1208
|
+
= Asynchronous(('note:(非同期)'))
|
1209
|
+
|
1210
|
+
# coderay ruby
|
1211
|
+
|
1212
|
+
# Call with block
|
1213
|
+
client.select(table: "docs",
|
1214
|
+
match_columns: "content",
|
1215
|
+
query: "concat") do |response|
|
1216
|
+
p response.n_hits # => 1
|
1217
|
+
end
|
1218
|
+
p :here # => :here then ↑
|
1219
|
+
sleep(0.1)
|
1220
|
+
|
1221
|
+
= Asynchronous - wait
|
1222
|
+
|
1223
|
+
# coderay ruby
|
1224
|
+
|
1225
|
+
request =
|
1226
|
+
client.select(table: "docs",
|
1227
|
+
match_columns: "content",
|
1228
|
+
query: "concat") do |response|
|
1229
|
+
p response.n_hits # => 1
|
1230
|
+
end
|
1231
|
+
p :here # => :here then ↑
|
1232
|
+
request.wait
|
1233
|
+
|
1234
|
+
= groonga-client-rails
|
1235
|
+
|
1236
|
+
Ruby on Rails\n
|
1237
|
+
integration\n
|
1238
|
+
for\n
|
1239
|
+
groonga-client\n
|
1240
|
+
(('note:Ruby on Railsで使う'))
|
1241
|
+
|
1242
|
+
= Architecture\n(('note:アーキテクチャー'))
|
1243
|
+
|
1244
|
+
* Data: RDBMS\n
|
1245
|
+
(('note:データはRDBMSに格納'))
|
1246
|
+
* Full text search: Groonga\n
|
1247
|
+
(('note:全文検索はGroongaで処理'))
|
1248
|
+
|
1249
|
+
= Define app searcher\n(('note:アプリ用サーチャーを定義'))
|
1250
|
+
|
1251
|
+
# coderay ruby
|
1252
|
+
|
1253
|
+
# app/searchers/application_searcher.rb
|
1254
|
+
class ApplicationSearcher <
|
1255
|
+
Groonga::Client::Searcher
|
1256
|
+
end
|
1257
|
+
|
1258
|
+
= Define searcher\n(('note:サーチャーを定義'))
|
1259
|
+
|
1260
|
+
# coderay ruby
|
1261
|
+
|
1262
|
+
# app/searchers/document_searcher.rb
|
1263
|
+
class DocumentsSearcher < ApplicationSearcher
|
1264
|
+
# Define a full text search index as "content"
|
1265
|
+
# 全文検索用のインデックスを定義
|
1266
|
+
schema.column :content, {
|
1267
|
+
type: "Text",
|
1268
|
+
index: true,
|
1269
|
+
index_type: :full_text_search,
|
1270
|
+
}
|
1271
|
+
end
|
1272
|
+
|
1273
|
+
= Bind to model\n(('note:モデルと結びつける'))
|
1274
|
+
|
1275
|
+
# coderay ruby
|
1276
|
+
|
1277
|
+
# app/models/document.rb
|
1278
|
+
class Document < ApplicationRecord
|
1279
|
+
# DocumentsSearcher searches Document model
|
1280
|
+
source = DocumentsSearcher.source(self)
|
1281
|
+
# Bind Document's "content" column to
|
1282
|
+
# DocumentsSearcher's "content" index
|
1283
|
+
source.content = :content
|
1284
|
+
end
|
1285
|
+
|
1286
|
+
= Search(('note:(検索)'))
|
1287
|
+
|
1288
|
+
# coderay ruby
|
1289
|
+
|
1290
|
+
# app/controllers/documents_controller.rb
|
1291
|
+
class DocumentsController < ApplicationController
|
1292
|
+
def index
|
1293
|
+
@query = params[:query]
|
1294
|
+
searcher = DocumentSearcher.new
|
1295
|
+
@result_set = searcher.search.
|
1296
|
+
query(@query).
|
1297
|
+
result_set
|
1298
|
+
end
|
1299
|
+
end
|
1300
|
+
|
1301
|
+
= See also\n(('note:参考情報'))
|
1302
|
+
|
1303
|
+
* Tutorial in Japanese\n
|
1304
|
+
(('note:日本語のチュートリアル'))
|
1305
|
+
* (('tag:xx-small'))
|
1306
|
+
((<URL:http://www.clear-code.com/blog/2016/12/22.html>))
|
1307
|
+
|
1308
|
+
= Groonga
|
1309
|
+
|
1310
|
+
mruby embedded\n
|
1311
|
+
full text search engine\n
|
1312
|
+
(('note:mruby組込の全文検索エンジン'))
|
1313
|
+
|
1314
|
+
= How mruby is used?\n(('note:mrubyの使い方'))
|
1315
|
+
|
1316
|
+
* Optimizer\n
|
1317
|
+
(('note:オプティマイザー'))
|
1318
|
+
* Custom command\n
|
1319
|
+
(('note:カスタムコマンド'))
|
1320
|
+
|
1321
|
+
= Custom command\n(('note:カスタムコマンド'))
|
1322
|
+
|
1323
|
+
# coderay ruby
|
1324
|
+
|
1325
|
+
module Sharding
|
1326
|
+
class LogicalSelectCommand < Groonga::Command
|
1327
|
+
# ...
|
1328
|
+
end
|
1329
|
+
end
|
1330
|
+
|
1331
|
+
= Use cases\n(('note:利用例'))
|
1332
|
+
|
1333
|
+
* Redmine plugin\n
|
1334
|
+
(('note:Redmineのプラグイン'))
|
1335
|
+
* (('tag:x-small'))
|
1336
|
+
Repository: ((<URL:https://github.com/clear-code/redmine_full_text_search>))
|
1337
|
+
* (('tag:x-small'))
|
1338
|
+
Slide (in Japanese): ((<URL:https://slide.rabbit-shocker.org/authors/kou/redmine-tokyo-12/>))
|
1339
|
+
* ...
|
1340
|
+
|
1341
|
+
= Ranguba (WIP)(('note:(開発中)'))
|
1342
|
+
|
1343
|
+
Full text search system\n
|
1344
|
+
(('note:全文検索システム'))
|
1345
|
+
|
1346
|
+
= Use cases\n(('note:利用例'))
|
1347
|
+
|
1348
|
+
* File server search\n
|
1349
|
+
(('note:ファイルサーバー検索'))
|
1350
|
+
* Mail search\n
|
1351
|
+
(('note:メール検索'))
|
1352
|
+
* Web site search\n
|
1353
|
+
(('note:Webサイト検索'))
|
1354
|
+
|
1355
|
+
= Features\n(('note:機能'))
|
1356
|
+
|
1357
|
+
* Crawlers\n
|
1358
|
+
(('note:クローラー'))
|
1359
|
+
* Web UI
|
1360
|
+
* CLI
|
1361
|
+
* Update documents\n
|
1362
|
+
(('note:更新'))
|
1363
|
+
* Search documents\n
|
1364
|
+
(('note:検索'))
|
1365
|
+
|
1366
|
+
= ChupaText
|
1367
|
+
|
1368
|
+
Text extractor\n
|
1369
|
+
(('note:テキスト抽出'))
|
1370
|
+
|
1371
|
+
= Supported formats\n(('note:対応フォーマット'))
|
1372
|
+
|
1373
|
+
* PDF
|
1374
|
+
* Office documents(('note:(オフィス文書)'))
|
1375
|
+
* OpenDocument, Word, Excel, ...
|
1376
|
+
* E-mail(('note:(メール)'))
|
1377
|
+
* ...
|
1378
|
+
|
1379
|
+
= Interface\n(('note:インターフェイス'))
|
1380
|
+
|
1381
|
+
* HTTP
|
1382
|
+
* Web UI
|
1383
|
+
* CLI
|
1384
|
+
* API (Library)
|
1385
|
+
|
1386
|
+
= Install - Docker
|
1387
|
+
|
1388
|
+
# coderay console
|
1389
|
+
% GITHUB=https://github.com
|
1390
|
+
% git clone \
|
1391
|
+
${GITHUB}/ranguba/chupa-text-docker.git
|
1392
|
+
% cd chupa-text-docker
|
1393
|
+
% docker-compose up --build
|
1394
|
+
|
1395
|
+
= How to use\n(('note:使い方'))
|
1396
|
+
|
1397
|
+
# coderay console
|
1398
|
+
% curl \
|
1399
|
+
--form data=@XXX.pdf \
|
1400
|
+
http://localhost:20080/extraction.json
|
1401
|
+
|
1402
|
+
= Use cases\n(('note:利用例'))
|
1403
|
+
|
1404
|
+
* Ranguba
|
1405
|
+
* Full text search system\n
|
1406
|
+
(('note:全文検索システム'))
|
1407
|
+
* Commit e-mail\n
|
1408
|
+
(('note:コミットメール'))
|
1409
|
+
|
1410
|
+
= git-commit-mailer
|
1411
|
+
|
1412
|
+
Commit e-mail for Git\n
|
1413
|
+
(('note:Git用のコミットメール'))
|
1414
|
+
|
1415
|
+
= Features\n(('note:機能'))
|
1416
|
+
|
1417
|
+
* HTML mail\n
|
1418
|
+
(('note:HTMLメール'))
|
1419
|
+
* Highlighted diff\n
|
1420
|
+
(('note:diffをハイライト'))
|
1421
|
+
* GitLab/GitHub Web hook support\n
|
1422
|
+
(('note:GitLab/GitHubのWebフックをサポート'))
|
1423
|
+
* (('tag:xx-small'))
|
1424
|
+
By ((<"GitHub:clear-code/github-web-hooks-receiver"|URL:https://github.com/clear-code/github-web-hooks-receiver>))
|
1425
|
+
|
1426
|
+
= Users\n(('note:利用者'))
|
1427
|
+
|
1428
|
+
* tDiary
|
1429
|
+
* My products
|
1430
|
+
|
1431
|
+
= commit-email.info
|
1432
|
+
|
1433
|
+
Commit e-mail\n
|
1434
|
+
as a\n
|
1435
|
+
Service\n
|
1436
|
+
(('note:コミットメールのクラウドサービス'))
|
1437
|
+
|
1438
|
+
= How to use\n(('note:使い方'))
|
1439
|
+
|
1440
|
+
* Send a pull request to\n
|
1441
|
+
((<"GitHub:kou/commit-email.info"|URL:https://github.com/kou/commit-email.info>))\n
|
1442
|
+
(('note:pull requestを送る'))
|
1443
|
+
* Register a Web hook\n
|
1444
|
+
(('note:Webフックを登録'))
|
1445
|
+
* Subscribe your mailing list\n
|
1446
|
+
(('note:メーリングリストを購読'))
|
1447
|
+
|
1448
|
+
(('note:See also ((<URL:http://www.commit-email.info/>))'))
|
1449
|
+
|
1450
|
+
= Category5\n(('note:分類5'))
|
1451
|
+
|
1452
|
+
Data processing\n
|
1453
|
+
(('note:データ処理'))
|
1454
|
+
|
1455
|
+
= csv
|
1456
|
+
|
1457
|
+
CSV parser\n
|
1458
|
+
(('note:CSVパーサー'))
|
1459
|
+
|
1460
|
+
= csv - History\n(('note:歴史'))
|
1461
|
+
|
1462
|
+
* 2003: Import\n
|
1463
|
+
(('note:Rubyに取り込み'))
|
1464
|
+
* 2007: Replaced with FasterCSV\n
|
1465
|
+
(('note:FasterCSVで置き換え'))
|
1466
|
+
* 2018: I became a co-maintainer with mrkn\n
|
1467
|
+
(('note:mrknと一緒にメンテナーになった'))
|
1468
|
+
|
1469
|
+
= Why?\n(('note:なんで?'))
|
1470
|
+
|
1471
|
+
* There are many CSV data\n
|
1472
|
+
(('note:CSVのデータはたくさんある'))
|
1473
|
+
* Important to process data\n
|
1474
|
+
(('note:データを処理するためにCSVパーサーは重要'))
|
1475
|
+
|
1476
|
+
= CSV format problems\n(('note:CSVフォーマットの問題'))
|
1477
|
+
|
1478
|
+
* Slow to parse\n
|
1479
|
+
(('note:パースが遅い'))
|
1480
|
+
* Too wild\n
|
1481
|
+
(('note:なんでもあり'))
|
1482
|
+
|
1483
|
+
= Red Arrow
|
1484
|
+
|
1485
|
+
Apache Arrow Ruby
|
1486
|
+
|
1487
|
+
= Red Arrow - History\n(('note:歴史'))
|
1488
|
+
|
1489
|
+
* 2017-02: The first commit\n
|
1490
|
+
(('note:最初のコミット'))
|
1491
|
+
* 2018-05: Became the "official" Ruby bindings of Apache Arrow\n
|
1492
|
+
(('note:Apache Arrowの公式Rubyバインディングになった'))
|
1493
|
+
|
1494
|
+
= Apache Arrow
|
1495
|
+
|
1496
|
+
* Super fast data format\n
|
1497
|
+
(('note:すごく速いデータフォーマット'))
|
1498
|
+
* For in-memory data\n
|
1499
|
+
(('note:インメモリーデータ用'))
|
1500
|
+
* Cross-language support\n
|
1501
|
+
(('note:いろんな言語がサポート'))
|
1502
|
+
* Easy to share data with Python, Java, ...\n
|
1503
|
+
(('note:PythonやJavaなどとデータ交換がしやすい'))
|
1504
|
+
|
1505
|
+
= Apache Arrow - Position\n(('note:立ち位置'))
|
1506
|
+
|
1507
|
+
* A very important peace\n
|
1508
|
+
in recent data processing\n
|
1509
|
+
(('note:最近のデータ処理界隈ではすごく大事な1ピース'))
|
1510
|
+
* Like JIT for Ruby 3\n
|
1511
|
+
(('note:Ruby 3で例えるとJITみたいな感じ'))
|
1512
|
+
|
1513
|
+
= Red Arrow - Impl.\n(('note:実装'))
|
1514
|
+
|
1515
|
+
* Based on Ruby/GI\n
|
1516
|
+
(('note:Ruby/GIを使っている'))
|
1517
|
+
* Auto generated bindings\n
|
1518
|
+
(('note:バインディングを自動生成'))
|
1519
|
+
|
1520
|
+
= Red Data Tools
|
1521
|
+
|
1522
|
+
A project to make Ruby data processable\n
|
1523
|
+
(('note:Rubyでデータ処理できるようにするためのプロジェクト'))
|
1524
|
+
|
1525
|
+
= Red Data Tools - History\n(('note:歴史'))
|
1526
|
+
|
1527
|
+
* 2017-02: Start(('note:(開始)'))
|
1528
|
+
* 2017-11-: Develop events per month at Tokyo at Speee. Inc,\n
|
1529
|
+
(('note:東京のSpeeeさんで毎月開発イベントを開催'))
|
1530
|
+
|
1531
|
+
= The number of products\n(('note:プロダクト数'))
|
1532
|
+
|
1533
|
+
About 20\n
|
1534
|
+
(('note:20くらい'))
|
1535
|
+
|
1536
|
+
= Red Datasets
|
1537
|
+
|
1538
|
+
Dataset fetcher\n
|
1539
|
+
(('note:データセット取得'))
|
1540
|
+
|
1541
|
+
= Supported datasets\n(('note:対応データセット'))
|
1542
|
+
|
1543
|
+
* Iris
|
1544
|
+
* CIFAR
|
1545
|
+
* Wikipedia
|
1546
|
+
|
1547
|
+
= Wikipedia
|
1548
|
+
|
1549
|
+
# coderay ruby
|
1550
|
+
|
1551
|
+
require "datasets"
|
1552
|
+
|
1553
|
+
wikipedia = Datasets::WikiPedia.new
|
1554
|
+
wikipedia.each do |page|
|
1555
|
+
p page.title
|
1556
|
+
end
|
1557
|
+
|
1558
|
+
= Wikipedia search
|
1559
|
+
|
1560
|
+
# coderay ruby
|
1561
|
+
|
1562
|
+
pages = Groonga["pages"]
|
1563
|
+
wikipedia = Datasets::WikiPedia.new
|
1564
|
+
wikipedia.each do |page|
|
1565
|
+
pages.add(title: page.title,
|
1566
|
+
content: page.revision.text)
|
1567
|
+
end
|
1568
|
+
ruby_pages = pages.select do |record|
|
1569
|
+
record.match("Ruby")
|
1570
|
+
end
|
1571
|
+
p ruby_pages.n_hits
|
1572
|
+
|
1573
|
+
= jekyll-jupyter-notebook
|
1574
|
+
|
1575
|
+
Jekyll\n
|
1576
|
+
(('+'))\n
|
1577
|
+
Jupyter Notebook
|
1578
|
+
|
1579
|
+
= Usage\n(('note:使い方'))
|
1580
|
+
|
1581
|
+
{% jupyter_notebook sample.ipynb %}
|
1582
|
+
|
1583
|
+
= Red OpenCV
|
1584
|
+
|
1585
|
+
Computer vision\n
|
1586
|
+
(('note:コンピュータービジョン'))
|
1587
|
+
|
1588
|
+
= Camera(('note:(カメラ)'))
|
1589
|
+
|
1590
|
+
# coderay ruby
|
1591
|
+
|
1592
|
+
require "cv"
|
1593
|
+
camera = CV::Camera.new
|
1594
|
+
image = camera.read
|
1595
|
+
image.write("capture.jpg")
|
1596
|
+
|
1597
|
+
= Face detect(('note:(顔認識)'))
|
1598
|
+
|
1599
|
+
# coderay ruby
|
1600
|
+
|
1601
|
+
image_gray = image.convert_color(:bgr2gray)
|
1602
|
+
classifier = # Face detector
|
1603
|
+
CV::CascadeClassifier.new("frontalface_alt")
|
1604
|
+
objects = classifier.detect(image_gray)
|
1605
|
+
color = CV::Color.new(0, 0, 255)
|
1606
|
+
objects.each do |object|
|
1607
|
+
# Draw detected area
|
1608
|
+
image.draw_rectangle(object, color)
|
1609
|
+
end
|
1610
|
+
image.write("detect.jpg")
|
1611
|
+
|
1612
|
+
= Red OpenCV - Impl.\n(('note:実装'))
|
1613
|
+
|
1614
|
+
* Based on Ruby/GI\n
|
1615
|
+
(('note:Ruby/GIを使っている'))
|
1616
|
+
* Auto generated bindings\n
|
1617
|
+
(('note:バインディングを自動生成'))
|
1618
|
+
|
1619
|
+
= Ad: RubyData Workshop\n(('note:宣伝:RubyDataワークショップ'))
|
1620
|
+
|
1621
|
+
* 2018-06-01 15:50/17:20
|
1622
|
+
* Contents:(('note:(内容)'))
|
1623
|
+
* Workshop by mrkn\n
|
1624
|
+
(('note:mrknによるワークショップ'))
|
1625
|
+
* Presentations what Red Data Tools did by members\n
|
1626
|
+
(('note:Red Data ToolsメンバーによるRed Data Toolsでやってきたことの紹介'))
|
1627
|
+
|
1628
|
+
= Process data with Ruby\n(('note:Rubyでデータ処理'))
|
1629
|
+
|
1630
|
+
* We're working on it\n
|
1631
|
+
(('note:Red Data Toolsは継続して取り組んでいる'))
|
1632
|
+
* Do you want to work with us?\n
|
1633
|
+
(('note:一緒にやりたい人はいる?'))
|
1634
|
+
|
1635
|
+
= How to join1(('note:(参加方法1)'))
|
1636
|
+
|
1637
|
+
* Join our chat rooms:\n
|
1638
|
+
(('note:チャットルームに参加'))
|
1639
|
+
* en: ((<"Gitter:red-data-tools/en"|URL:https://gitter.im/red-data-tools/en>))
|
1640
|
+
* ja: ((<"Gitter:red-data-tools/ja"|URL:https://gitter.im/red-data-tools/ja>))
|
1641
|
+
* Join monthly events at Tokyo\n
|
1642
|
+
(('note:東京での毎月の開発イベントに参加'))
|
1643
|
+
* ((<URL:https://speee.connpass.com/>))
|
1644
|
+
|
1645
|
+
= How to join2(('note:(参加方法2)'))
|
1646
|
+
|
1647
|
+
* Hire a developer to work on\n
|
1648
|
+
(('note:この問題に取り組む開発者を雇う'))
|
1649
|
+
* e.g.: mrkn by Speee, Inc.\n
|
1650
|
+
(('note:例:Speeeのmrkn'))
|
1651
|
+
|
1652
|
+
= How to join3(('note:(参加方法3)'))
|
1653
|
+
|
1654
|
+
* Order ClearCode to work on it\n
|
1655
|
+
(('note:クリアコードに開発の仕事を発注'))
|
1656
|
+
* Join ClearCode to work on it\n
|
1657
|
+
(('note:クリアコードに入って仕事として開発を進める'))
|
1658
|
+
|
1659
|
+
= Wrap up\n(('note:まとめ'))
|
1660
|
+
|
1661
|
+
* I'm working on the followings as a Rubyist\n
|
1662
|
+
(('note:Rubyistとしての私の活動'))
|
1663
|
+
* Increase what Ruby can\n
|
1664
|
+
(('note:Rubyでできることを増やす'))
|
1665
|
+
* Maintain libraries\n
|
1666
|
+
(('note:ライブラリーのメンテナス'))
|
1667
|
+
* Do you want to work with me?\n
|
1668
|
+
(('note:一緒にやりたい人はいる?'))
|