My way with Ruby¶ ↑
: author
Kouhei Sutou
: institution
ClearCode Inc.
: content-source
RubyKaigi 2018
: date
2018-06-01
: start-time
2018-06-01T09:40:00+09:00
: end-time
2018-06-01T10:35:00+09:00
: theme
.
Ad: Silver sponsor¶ ↑
# img # src = images/clear-code-rubykaigi-2018-silver-sponsor.png # relative_height = 100 # reflect_ratio = 0.1
Slide properties¶ ↑
: enable-title-on-image
false
Acknowledgmentn(('note:感謝'))¶ ↑
(('tag:center')) @drbrainn Eric Hodel
(('tag:center')) He fixed English in this sliden (('note:英語をチェックしてくれたよ!ありがとう!'))
Keynote-ish topicn(('note:キーノートっぽい話題'))¶ ↑
Did you think about it?n (('note:考えたことある?'))
Keynote-ish topic1n(('note:キーノートっぽい話題1'))¶ ↑
Futuren (('note:未来のこと'))
Keynote-ish topic2n(('note:キーノートっぽい話題2'))¶ ↑
Focus onn one thingn ((deeply))n (('note:なにかを深掘り'))
Keynote-ish topic3n(('note:キーノートっぽい話題3'))¶ ↑
Overviewn (('note:俯瞰した話'))
My activitiesnas a Rubyistn(('note:私のRubyist活動'))¶ ↑
* Increase what Ruby can do\n with free software\n (('note:フリーソフトウェアを使ってRubyでできることを増やす')) * Maintain libraries\n (('note:ライブラリーのメンテナンス'))
# of libraries maintainedn(('note:メンテナンスしているライブラリー数'))¶ ↑
About 130n (('note:130くらい'))
Today's topicn(('note:今日の話題'))¶ ↑
Overviewn what we can don ((*with Ruby*))n (('note:Rubyでできるようになったことをたくさん紹介'))
How to find targets?n(('note:そんなにネタがあるの?'))¶ ↑
Just I neededn (('note:単に自分が必要だったから'))
Opening1n(('note:きっかけ1'))¶ ↑
Web feedn (('note:Webフィード'))
RSS Parser¶ ↑
RSS/Atom parsern withn ((validation))n (('note:バリデーション機能付きのRSS/Atomパーサー'))
RSS Parser - Historyn(('note:歴史'))¶ ↑
* 2003-05: The first release\n (('note:最初のリリース')) * No other RSS/Atom parser that supports validation even now\n (('note:今でもバリデーション付きのパーサーは他にない')) * 2004-01: Ruby bundles this\n (('note:RubyがRSS Parserをバンドル')) * I became a Ruby committer\n (('note:Rubyコミッターになる'))
Validate RSS/Atomn(('note:RSS/Atomのバリデーション'))¶ ↑
* Important for me\n (('note:私にとっては大事')) * Most wild RSS/Atom feeds are\n ((*invalid*))\n (('note:野生のRSS/Atomの多くは不正')) * Validation helps to find problems\n (('note:バリデーションがあると問題を見つけやすくなる'))
RSS::Parser.parse¶ ↑
# coderay ruby # Validates by default # デフォルトでバリデーション RSS::Parser.parse(rss) # Validation can be disabled # 無効にできる RSS::Parser.parse(rss, false)
Since Ruby 2.6n(('note:Ruby 2.6以降'))¶ ↑
# coderay ruby # Supports keyword argument # キーワード引数対応 parse(rss, validate: false)
REXML¶ ↑
XML parsern written inn ((*pure Ruby*))n (('note:Ruby実装のXMLパーサー'))
REXML - Historyn(('note:歴史'))¶ ↑
* 2001: Started by Sean Russell\n (('note:Seanさんが開発を開始')) * Based on Electric XML (Java)\n (('note:Java実装のElectric XMLを参考に開発')) * REXML is "Ruby Electric XML"\n (('note:REXMLは「Ruby Electric XML」')) * 2003-01: Ruby bundles this\n (('note:RubyがREXMLをバンドル'))
REXML - Side storyn(('note:おまけ話'))¶ ↑
* Sean was "書運" in Kanji\n (('note:Seanさんには「書運」という漢字表記があった')) * He was interested in Japan\n (('note:日本好きだった')) * (('tag:x-small'))"How to write your name in Kanji?"\n (('note:「君の名前は漢字でどう書くの?」')) * We can connect with Ruby!\n (('note:RubyistはRubyをきっかけにつながれる!'))
Ad: Code Partyn(('note:宣伝:コード懇親会'))¶ ↑
# img # src = images/code-party.png # relative_height = 100 # reflect_ratio = 0.1
Slide properties¶ ↑
: enable-title-on-image
false
Ad: Code Partyn(('note:宣伝:コード懇親会'))¶ ↑
(('tag:center')) This is a challengen (('note:実験的な企画'))
* Ruby focus: to have fun\n (('note:Rubyは楽しさを大事にしている')) * We have fun writing Ruby\n (('note:Rubyistは楽しくRubyを書いている')) * We have fun together with writing Ruby at after party!?\n (('note:だったら懇親会で一緒にRubyを書くと楽しそう!?'))
Ad: Code Partyn(('note:宣伝:コード懇親会'))¶ ↑
* Matz attends Code Party\n (('note:まつもとさんもコード懇親会に参加')) * Sponsored by Speee, Inc.\n (('note:Speeeさんがスポンサー'))
REXML - Recent1n(('note:最近1'))¶ ↑
* 2010-08: RubyKaigi 2010 * I became the maintainer\n (('note:私がメンテナーになった')) * Because RSS Parser uses it\n (('note:RSS Parserが使っているから'))
REXML - Recent2n(('note:最近2'))¶ ↑
* 2016: (({element[attribute_name]})) * Ruby 2.5 ships it\n (('note:Ruby 2.5以降で使える'))
REXML - Recent3n(('note:最近3'))¶ ↑
* 2018: Fix XPath related bugs\n (('note:XPath関連のバグ修正')) * Ruby 2.6 ships it\n (('note:Ruby 2.6以降で使える'))
REXML - Future?n(('note:未来はあるの?'))¶ ↑
* ((*Pure Ruby*)) is valuable\n (('note:Rubyだけで書かれていることには価値がある')) * Easy to install\n (('note:インストールが簡単')) * JIT may improve performance\n (('note:NOTE: We should improve general logic before we expect JIT to improve performance😉'))\n (('note:JITで速くなるかもしれない'))\n (('note:JITの前に普通にロジックを改良するのが先だけどね😉'))\n
Recent my worksn(('note:最近の仕事'))¶ ↑
* XML/HTML libraries for LuaJIT\n (('note:LuaJIT用のXML/HTMLライブラリー')) * XMLua: (('tag:xx-small:((<URL:https://clear-code.github.io/xmlua/>))'))\n libxml2 based XML/HTML parser * LuaCS: (('tag:xx-small:((<URL:https://clear-code.github.io/luacs/>))'))\n CSS Selectors→XPath converter * Found what is lacking in REXML API\n (('note:REXMLのAPIに足りないものはなにか考えた'))
REXML - Future1n(('note:未来1'))¶ ↑
Introduce NodeSetn (('note:NodeSetが足りないんじゃないか'))
REXML - NodeSet¶ ↑
# coderay ruby doc. search("//list"). # => NodeSet search("item"). # => All <item> in <list> text # All texts in <item> in <list>
REXML - Future2n(('note:未来2'))¶ ↑
Supportn CSS Selectorsn (('note:CSSセレクターが足りないんじゃないか'))
REXML - CSS Selectorsn(('note:CSSセレクター'))¶ ↑
# coderay ruby doc.css_select("ul li, dl dt")
REXML - Future3n(('note:未来3'))¶ ↑
Supportn HTML5 supportn (('note:HTML5対応が足りないんじゃないか'))
REXML - HTML5¶ ↑
# coderay ruby doc = REXML::HTML5Document.new(html5) doc.search("//li") doc.css_select("ul li")
REXML - Futuren(('note:未来'))¶ ↑
* Low priority in my activities\n (('note:優先度は高くない')) * Do you want to work with me?\n (('note:一緒にやりたい人はいる?'))
Opening2n(('note:きっかけ1'))¶ ↑
Presentationn (('note:プレゼンテーション'))
Rabbit¶ ↑
(('tag:center')) (('tag:large')) Presentation tooln for ((Rubyist))n (('note:Rubyist用のプレゼンツール'))
((' '))
Rabbit - Historyn(('note:歴史'))¶ ↑
* 2004-07: The first release\n (('note:最初のリリース')) * No other presentation tool for a Rubyist even now\n (('note:今でもRubyist用のプレゼンツールは他にない')) * 2010: Matz migrated to Rabbit\n (('note:まつもとさんがRabbitに乗り換えた')) * Since RubyKaigi 2010?\n (('note:RubyKaigi 2010から?'))
For Rubyist?n(('note:Rubyist向けに必要なもの'))¶ ↑
RD supportn (('note:RDサポート'))
RD¶ ↑
* ((*R*))uby ((*D*))ocument\n * Designed by Matz (('note:(Right?)'))\n (('note:まつもとさんがデザインしたはず')) * A text based markup language\n (('note:テキストベースのマークアップ言語')) * Version controllable\n (('note:バージョン管理できる'))
For Rubyist?n(('note:Rubyist向けに必要なもの'))¶ ↑
Publishn our slidesn as usualn (('note:いつも通りスライドを公開できる'))
Publish as usualn(('note:いつも通り公開'))¶ ↑
# coderay console % gem push your-slide-1.0.gem
Published!n(('note:公開完了!'))¶ ↑
# img # src = images/rabbit-slide-show.png # relative_height = 78
(('tag:center')) (('tag:small')) ((<URL:slide.rabbit-shocker.org/>))
What's needed for presentation tool?n(('note:プレゼンツールに必要なもの'))¶ ↑
GUI
Ruby/GTK3¶ ↑
Multi-platform GUI toolkitn (('note:複数プラットフォーム対応GUIツールキット'))
Ruby/GTK3 - Historyn(('note:歴史'))¶ ↑
* 1998-01: 1st release by Matz\n ((<[ruby-list:5877]|URL:http://blade.nagaokaut.ac.jp/cgi-bin/scat.rb/ruby/ruby-list/5877>))\n (('note:まつもとさんが最初のリリース')) * 2004-05: I joined development\n (('note:私が開発に参加'))
Example - Window¶ ↑
# coderay ruby require "gtk3" app = Gtk::Application.new app.signal_connect(:activate) do window = Gtk::ApplicationWindow.new(app) window.show_all end app.run
Approaches onnmissing libraries(1)n(('note:ライブラリーがない時のやり方(1)'))¶ ↑
(1) Implement only the needed features\n (('note:必要な機能だけ実装')) (2) then back to Rabbit\n (('note:必要な機能ができたらRabbitに戻る'))
Approaches onnmissing libraries(2)n(('note:ライブラリーがない時のやり方(2)'))¶ ↑
(1) Implement not only the needed features\n (('note:必要な機能だけじゃなく')) (2) but also (('note:almost')) all features\n (('note:ほぼすべての機能を実装')) (3) then back to Rabbit\n (('note:終わったらRabbitに戻る'))
My approachn(('note:私のやり方'))¶ ↑
Implementn all featuresn (('note:testing with Rabbit'))n (('note:すべての機能を実装'))
My priorityn(('note:私の優先度'))¶ ↑
* Rabbit is important\n (('note:Rabbitは大事だけど')) * Increasing what Ruby can do is important too\n (('note:Rubyでできることを増やすのも大事'))
GTK+ 3 - Sizen(('note:サイズ'))¶ ↑
3000 over APIsn (('note:3000以上のAPI'))
How to implementn(('note:実装方法'))¶ ↑
Handwritingn (('note:手書き'))n ↓n Auto generationn (('note:自動生成'))
Ruby/GI¶ ↑
(('tag:center')) (('tag:large')) Generate bindingsn automaticallyn at run-timen (('note:実行時に自動でバインディングを生成'))
(('note:GI: GObject Introspection'))
Ruby/GI - Historyn(('note:歴史'))¶ ↑
* 2012: The first commit by me\n (('note:最初のコミット')) * 2014: Ruby/GTK3 used Ruby/GI\n (('note:Ruby/GTK3をRuby/GIベースに移行'))
Handwritingn(('note:手書き'))¶ ↑
# img # src = images/ruby-gtk3-without-ruby-gi.svg # relative_width = 100
Slide properties¶ ↑
: enable-title-on-image
false
Auto generationn(('note:自動生成'))¶ ↑
# img # src = images/ruby-gtk3-with-ruby-gi.svg # relative_width = 100
Slide properties¶ ↑
: enable-title-on-image
false
Performance(('note:(性能)'))¶ ↑
* Slower than handwriting\n (('note:手書きより遅い')) * Overhead\n (('note:オーバーヘッド')) * Dynamic arguments conversion\n (('note:動的な引数の変換')) * libffi based function call\n (('note:libffiを使った関数呼び出し'))
Improve idea(('note:(改善案)'))¶ ↑
JIT compilingn (('note:JITコンパイル'))
JIT compiling(('note:(JITコンパイル)'))¶ ↑
# coderay c VALUE rb_method_generic() { func = dlsym(name); ... ffi_call(func, ..., &result); return C2RB(result); } ↓ // Build rb_method() at run-time and call it. VALUE rb_method() {return C2RB(name(...));}
Ruby/GI - See alson(('note:参考情報'))¶ ↑
* "How to create bindings 2016" at RubyKaigi 2016\n * (('tag:xx-small')) ((<URL:http://rubykaigi.org/2016/presentations/ktou.html>)) * "GI Introduction" (('note:(in Japanese)'))\n (('note:「GObject Introspection入門」')) * (('tag:xx-small')) ((<URL:https://github.com/RubyData/workshop-materials/blob/master/gobject-introspection/introduction.md>)) * Build system: Meson + Ninja\n (('note:ビルドシステム:Meson + Ninja'))
Ruby/GI based bindingsn(('note:Ruby/GIベースのバインディング'))¶ ↑
Ruby/Pango
Ruby/Pango¶ ↑
(('tag:center')) (('tag:large')) Text layout enginen withn i18n supportn (('note:国際化対応のテキストレイアウトエンジン'))
(('note:i18n: Internationalization'))
Prohibition processingn(('note:禁則処理'))¶ ↑
# coderay ruby widget.signal_connect(:draw) do |_, context| layout = context.create_pango_layout layout.text = "Helloこんにちは。🍣" context.show_pango_layout(layout) GLib::Source::CONTINUE end
Bidirectional textn(('note:双方向テキスト'))¶ ↑
Hello
مرحبا
こんにちは
Ruby/GI based bindingsn(('note:Ruby/GIベースのバインディング'))¶ ↑
Ruby/GdkPixbuf2
Ruby/GdkPixbuf2¶ ↑
Image manipulationn (('note:画像操作'))
Half imagen(('note:画像を半分に'))¶ ↑
# coderay ruby require "gdk_pixbuf2" # Load an image: Format is auto detected pixbuf = GdkPixbuf::Pixbuf.new(file: "x.png") # Scale to half size half = pixbuf.scale(pixbuf.width / 2, pixbuf.height / 2, :bilinear) # Save as different format half.save("half.jpg")
Animated GIFn(('note:アニメーションGIF'))¶ ↑
# img # src = images/the-tortoise-and-the-hare.gif # relative_width = 100
Slide properties¶ ↑
: enable-title-on-image
false
Ruby/GI based bindingsn(('note:Ruby/GIベースのバインディング'))¶ ↑
Ruby/Poppler
Ruby/Poppler¶ ↑
PDFn parser/renderern (('note:PDFパーサー・レンダラー'))
Text extractionn(('note:テキスト抽出'))¶ ↑
# coderay ruby require "poppler" doc = Poppler::Document.new("x.pdf") doc.each do |page| puts(page.text) # Extract all texts end
Embed PDFn(('note:PDFの埋め込み'))¶ ↑
# image # src = images/rubykaigi-2017-extension-by-cpp-title.pdf # relative_height = 80 # reflect_ratio = 0.1
(('tag:center')) (('tag:xx-small')) ((<URL:rubykaigi.org/2017/presentations/ktou.html>))
Slide properties¶ ↑
: enable-title-on-image
false
Ruby/GI based bindingsn(('note:Ruby/GIベースのバインディング'))¶ ↑
Ruby/GStreamer
Ruby/GStreamer¶ ↑
(('tag:center')) (('tag:large')) Audio/Video playern (('note:音声・動画プレイヤー'))
(('note:(*) Streaming media framework'))n (('note:本当はストリーミングメディアフレームワーク'))
Camera(('note:(カメラ)'))¶ ↑
# coderay ruby require "gst" description = [ "autovideosrc", # Camera "videoconvert", # Filter "autovideosink", # Window ].join(" ! ") pipeline = Gst.parse_launch(description) pipeline.play until pipeline.bus.poll.type.eos? do end # Main loop pipeline.stop
Face detection(('note:(顔認識)'))¶ ↑
# coderay ruby description = [ "autovideosrc", # Camera "videoconvert", # Filter "facedetect", # Face detection (!) "videoconvert", # Filter (!) "autovideosink", # Window ].join(" ! ") pipeline = Gst.parse_launch(description) pipeline.play
# = Embed video
# TODO
# # # video # # # src = test.mp4
What's needed for presentation tool?n(('note:プレゼンツールに必要なもの'))¶ ↑
PDF outputn (('note:PDF出力'))
rcairo¶ ↑
2D graphics renderern (('note:2次元画像レンダラー'))
rcairo - Outputsn(('note:出力'))¶ ↑
* PNG・SVG * ((*PDF*)) * ((*Display*)) (X/macOS/Windows) * ...
rcairo - Historyn(('note:歴史'))¶ ↑
* 2003-10: The initial commit\n (('note:最初のコミット')) * 2005-09: I started developing\n (('note:私が開発に参加'))
Red A4 PDFn(('note:赤いA4のPDFを出力'))¶ ↑
# coderay ruby require "cairo" include Cairo PDFSurface.create("x.pdf", "A4") do |surface| Context.create(surface) do |context| context.set_source_color(:red) context.paint end end
rcairo - GC¶ ↑
# image # src = images/cairo-no-gc-trigger.pdf # align = right # vertical_align = bottom # relative_width = 65 # relative_padding_right = -7 # relative_padding_bottom = -10 # coderay ruby 1000.times do Cairo::ImageSurface.new(:argb32, 6000, 6000) end
(('tag:margin-bottom * 20'))
GC - Cause(('note:(原因)'))¶ ↑
# image # src = images/cairo-no-gc-trigger.pdf # align = right # vertical_align = bottom # relative_width = 67 # relative_padding_right = -11 # relative_padding_bottom = -10 * GC isn't run often enough\n (('note:GCの実行頻度が十分じゃなかった')) * Because Ruby doesn't know how much memory used by cairo\n (('note:Rubyはcairoのメモリー使用量を知らないから'))
(('tag:margin-bottom * 16'))
GC - Fix(('note:(修正)'))¶ ↑
# image # src = images/cairo-gc-trigger.pdf # align = right # vertical_align = bottom # relative_width = 67 # relative_padding_right = -11 # relative_padding_bottom = -10 * (({rb_gc_adjust_memory_usage()})) * Improve GC frequency(('note:(GC実行頻度を改善)')) * Ruby 2.4 ships it(('note:(Ruby 2.4以降)'))
(('tag:margin-bottom * 18'))
What's needed for presentation tool?n(('note:プレゼンツールに必要なもの'))¶ ↑
Easy to installn (('note:簡単インストール'))
native-package-installer¶ ↑
Installn system packagesn on (({gem install}))n (('note:gem install時にシステムのパッケージをインストール'))
extconf.rb/Rakefile¶ ↑
# coderay ruby require "pkg-config" require "native-package-installer" unless PKGConfig.check_version?("gdk-3.0") packages = { altlinux: "libgtk+3-devel", debian: "libgtk-3-dev", redhat: "pkgconfig(gdk-3.0)", homebrew: "gtk+3", macports: "gtk3", msys2: "gtk3", } unless NativePackageInstaller.install(packages) exit(false) end end
rake-compiler¶ ↑
Build fat gemn byn cross compilen (('note:クロスコンパイルでfat gemをビルド'))
rake-compiler - Historyn(('note:歴史'))¶ ↑
* 2008-11: The first commit\n (('note:最初のコミット')) * 2014-12: Orphan\n (('note:だれかメンテナー変わってー')) * 2014-12:\n I became the maintainer\n (('note:私がメンテナーになった'))
Opening3n(('note:きっかけ3'))¶ ↑
Testn (('note:テスト'))
test-unit¶ ↑
Testing frameworkn to write testsn ((*in Ruby*))n (('note:Rubyでテストを書けるテスティングフレームワーク'))
test-unit - Historyn(('note:歴史'))¶ ↑
* 2003-02: Import to Ruby\n (('note:Rubyに取り込まれる')) * 2008-05:\n I became the maintainer\n (('note:私がメンテナーになった')) * 2008-10: Removed from Ruby\n (('note:Rubyから削除'))
(('note:See also: “The history of testing framework in Ruby”'))n (('tag:x-small'))((<URL:rubykaigi.org/2015/presentations/kou>))
test-unit - New featuren(('note:新機能'))¶ ↑
Groupingn (('note:グループ化'))
Groupingn(('note:グループ化'))¶ ↑
* The most important feature\n (('note:一番大事な機能')) * Keep tests maintainable\n (('note:メンテナンスできるテストを維持できる'))
Example(('note:(例)'))¶ ↑
# coderay ruby class StackTest < Test::Unit::TestCase class PushTest < self def test_XXX; end end class PopTest < self def test_XXX; end end end
Method style(('note:(メソッド形式)'))¶ ↑
# coderay ruby class StackTest < Test::Unit::TestCase sub_test_case("#push") do def test_XXX; end end sub_test_case("#pop") do def test_XXX; end end end
test-unit - New featuren(('note:新機能'))¶ ↑
Data driven testn (('note:データ駆動テスト'))
Data driven testn(('note:データ駆動テスト'))¶ ↑
# coderay ruby data("positive", [3, 1, 2]) data("negative", [-4, 1, -5]) def test_add(data) expected, augend, addend = data assert_equal(expected, add(augend, addend)) end
test-unit - New featuren(('note:新機能'))¶ ↑
Reverse backtracen (('note:逆順のバックトレース'))
Reverse backtracen(('note:逆順のバックトレース'))¶ ↑
* Reverse backtrace only for terminal output\n (('note:ターミナル出力のときだけ逆順')) * The same change as Ruby 2.5.0\n (('note:Ruby 2.5.0と同じ変更'))
test-unit - New featuren(('note:新機能'))¶ ↑
Test doublen (('note:テストダブル'))
test-unit-rr¶ ↑
RR integrationn (('note:RRとの統合'))
RR - Historyn(('note:歴史'))¶ ↑
* 2007-06: The initial commit\n (('note:最初のコミット')) * 2014-12: Orphan\n (('note:だれかメンテナー変わってー')) * 2015-05:\n I became the maintainer\n (('note:私がメンテナーになった'))
Stub(('note:(スタブ)'))¶ ↑
# coderay ruby adder = Object.new adder.add(1, 2) # => Error stub(adder).add(1, 2) {3} adder.add(1, 2) # => 3
Opening4n(('note:きっかけ4'))¶ ↑
Full text searchn (('note:全文検索'))
Rroonga¶ ↑
Full text searchn ((library))n (('note:全文検索ライブラリー'))
((Library)) vs Clientn(('note:ライブラリー対クライアント'))¶ ↑
* No server process\n (('note:サーバープロセスがいらない')) * Easy to start\n (('note:簡単に使い始められる')) * Write in Ruby\n (('note:Rubyで書ける'))
Create DB(('note:(データベース作成)'))¶ ↑
# coderay ruby require "groonga" Groonga::Database.create(path: "/tmp/db")
Define schema(('note:(スキーマ定義)'))¶ ↑
# coderay ruby Groonga::Schema.define do |schema| schema.create_table("docs") do |table| # The column to store text table.text("content") end # The index for full text search schema.create_lexicon("terms") do |table| table.index("docs.content") end end
Add records(('note:(レコード追加)'))¶ ↑
# coderay ruby docs = Groonga["docs"] docs.add(content: "String#<< concatenates ...") docs.add(content: "String#dup duplicates ...")
Search(('note:(検索)'))¶ ↑
# coderay ruby matches = docs.select do |record| record.content.match("concat") end p matches.size # => 1 matches.each do |record| p record.content # => "String#<< concat..." end
User - Rabbit Slide Show¶ ↑
# img # src = images/rabbit-slide-show.png # relative_height = 78
(('tag:center')) (('tag:small')) ((<URL:slide.rabbit-shocker.org/>))
User - Rurema Search¶ ↑
# img # src = images/rurema-search.png # relative_height = 78
(('tag:center')) (('tag:small')) ((<URL:docs.ruby-lang.org/ja/search/>))
Rurema Searchn(('note:るりまサーチ'))¶ ↑
* Super fast!\n (('note:すごく速い!')) * Tuned for Ruby documents\n (('note:Rubyのドキュメント用にチューニング'))
User - RDoc Search¶ ↑
* Planning\n (('note:考えてはいるけど。。。')) * Do you want to work with me?\n (('note:一緒にやりたい人はいる?'))
Rurema and RDoc¶ ↑
# RT Project, Language, Target Rurema, Japanese, Japanese Rubyists RDoc, English, All Rubyists
Sourcen(('note:ソース'))¶ ↑
* Shared nothing\n (('note:共有していない')) * Copy based share\n (('note:共有するときはコピー')) * e.g.:\n Description,\n Sample codes,\n ...\n (('note:例:説明やサンプルコードなどをコピー'))
From my point of viewn(('note:私が思うこと'))¶ ↑
* Can we share documents?\n (('note:ドキュメントを共有できないかな')) * How to work together deeply?\n (('note:もっと協力してできないかな'))
I18nn(('note:国際化'))¶ ↑
* Source: RDoc\n (('note:ソースはRDoc')) * For all Rubyists\n (('note:これは全Rubyist向け')) * Translate to Japanese\n (('note:RDocのドキュメントを日本語に翻訳')) * For Japanese Rubyists\n (('note:これは日本人Rubyist向け'))
Add i18n supportn(('note:国際化サポートを追加'))¶ ↑
* YARD * Since 0.8.0 at 2012-04 * RDoc * Since 4.2.0 at 2014-12
YARD - i18n¶ ↑
# coderay console # Generates po/yard.pot # po/yard.potを生成 % yard i18n
YARD - i18n¶ ↑
# coderay console # Create po/ja.po from po/yard.pot # po/yard.potからpo/ja.poを作成 % msginit \ --locale=ja_JP.UTF-8 \ --input=po/yard.pot \ --output-file=po/ja.po
YARD - i18n¶ ↑
# coderay console # Translate messages in po/ja.po # po/ja.po内のメッセージを翻訳 % editor po/ja.po
YARD - i18n¶ ↑
# coderay console # Generate documents with # translated messages # 翻訳したメッセージを使って # ドキュメント生成 % yard --locale ja
Packnga¶ ↑
Rake taskn forn YARD i18nn (('note:YARDの国際化機能向けのRakeタスク'))
Settingn(('note:設定'))¶ ↑
# coderay ruby # Rakefile require "packnga" Packnga::DocumentTask.new(spec) do |task| task.original_language = "en" task.translate_languages = ["ja"] end
Workflown(('note:ワークフロー'))¶ ↑
# coderay console % rake reference:translate % editor doc/po/ja/x.edit.po % rake reference:translate % editor lib/x.rb % rake reference:translate ...
Usersn(('note:ユーザー'))¶ ↑
* test-unit * Rroonga * ...
RDoc - i18n¶ ↑
# coderay console # Generates doc/rdoc.pot # doc/rdoc.potを生成 % rdoc --format=pot
RDoc - i18n¶ ↑
# coderay console # Create locale/ja.po # from doc/rdoc.pot # doc/rdoc.potからlocale/ja.poを作成 % mkdir -p locale % msginit \ --locale=ja_JP.UTF-8 \ --input=doc/rdoc.pot \ --output-file=locale/ja.po
RDoc - i18n¶ ↑
# coderay console # Translate messages in locale/ja.po # locale/ja.po内のメッセージを翻訳 % editor locale/ja.po
RDoc - i18n¶ ↑
# coderay console # Generate documents with # translated messages # 翻訳したメッセージを使って # ドキュメント生成 % rdoc --locale ja
RDoc, Rurema and i18n¶ ↑
* No progress...\n (('note:ツールの整備まででそれ以降は進んでいない。。。')) * Do you want to work with me?\n (('note:一緒にやりたい人はいる?'))
jekyll-task-i18n¶ ↑
Jekyll + i18n
Featuresn(('note:機能'))¶ ↑
* Support all markups!\n (('note:すべてのマークアップ対応!')) * GitHub Pages ready!\n (('note:GitHub Pagesでも使える!'))
Setting(('note:(設定)'))¶ ↑
# coderay ruby # Rakefile require "jekyll/task/i18n" Jekyll::Task::I18n.define do |task| task.locales = ["ja"] task.files = Rake::FileList["**/*.md"] task.files -= Rake::FileList["_*/**/*.md"] task.locales.each do |locale| task.files -= Rake::FileList["#{locale}/**/*.md"] end end task default: ["jekyll:i18n:translate"]
Workflow(('note:(ワークフロー)'))¶ ↑
% editor index.md % rake % editor _po/ja/index.edit.po % rake % git commit -a
User - Red Data Tools¶ ↑
# img # src = images/jekyll-task-i18n-red-data-tools.gif # relative_height = 78
(('tag:center')) (('tag:small')) ((<URL:red-data-tools.github.io/>))
groonga-client¶ ↑
Full text searchn ((client))n (('note:全文検索クライアント'))
Library vs ((Client))n(('note:ライブラリー対クライアント'))¶ ↑
* Less dependencies\n (('note:依存関係が少ない')) * Less resources needed\n (('note:必要なリソースが少ない'))
Search(('note:(検索)'))¶ ↑
# coderay ruby require "groonga/client" url = "http://localhost:10041" Groonga::Client.open(url: url) do |client| response = client.select(table: "docs", match_columns: "content", query: "concat") p response.n_hits # => 1 end
Asynchronous(('note:(非同期)'))¶ ↑
# coderay ruby # Call with block client.select(table: "docs", match_columns: "content", query: "concat") do |response| p response.n_hits # => 1 end p :here # => :here then ↑ sleep(0.1)
Asynchronous - wait¶ ↑
# coderay ruby request = client.select(table: "docs", match_columns: "content", query: "concat") do |response| p response.n_hits # => 1 end p :here # => :here then ↑ request.wait
groonga-client-rails¶ ↑
Ruby on Railsn integrationn forn groonga-clientn (('note:Ruby on Railsで使う'))
Architecturen(('note:アーキテクチャー'))¶ ↑
* Data: RDBMS\n (('note:データはRDBMSに格納')) * Full text search: Groonga\n (('note:全文検索はGroongaで処理'))
Define app searchern(('note:アプリ用サーチャーを定義'))¶ ↑
# coderay ruby # app/searchers/application_searcher.rb class ApplicationSearcher < Groonga::Client::Searcher end
Define searchern(('note:サーチャーを定義'))¶ ↑
# coderay ruby # app/searchers/document_searcher.rb class DocumentsSearcher < ApplicationSearcher # Define a full text search index as "content" # 全文検索用のインデックスを定義 schema.column :content, { type: "Text", index: true, index_type: :full_text_search, } end
Bind to modeln(('note:モデルと結びつける'))¶ ↑
# coderay ruby # app/models/document.rb class Document < ApplicationRecord # DocumentsSearcher searches Document model source = DocumentsSearcher.source(self) # Bind Document's "content" column to # DocumentsSearcher's "content" index source.content = :content end
Search(('note:(検索)'))¶ ↑
# coderay ruby # app/controllers/documents_controller.rb class DocumentsController < ApplicationController def index @query = params[:query] searcher = DocumentSearcher.new @result_set = searcher.search. query(@query). result_set end end
See alson(('note:参考情報'))¶ ↑
* Tutorial in Japanese\n (('note:日本語のチュートリアル')) * (('tag:xx-small')) ((<URL:http://www.clear-code.com/blog/2016/12/22.html>))
Ranguba (WIP)(('note:(開発中)'))¶ ↑
Full text search systemn (('note:全文検索システム'))
Use casesn(('note:利用例'))¶ ↑
* File server search\n (('note:ファイルサーバー検索')) * E-mail search\n (('note:メール検索')) * Web site search\n (('note:Webサイト検索'))
Featuresn(('note:機能'))¶ ↑
* Crawlers\n (('note:クローラー')) * Web UI * Command line interface * Update documents\n (('note:更新')) * Search documents\n (('note:検索'))
ChupaText¶ ↑
Text extractorn (('note:テキスト抽出'))
Supported formatsn(('note:対応フォーマット'))¶ ↑
* PDF * Office documents(('note:(オフィス文書)')) * OpenDocument, Word, Excel, ... * E-mail(('note:(メール)')) * ...
Interfacen(('note:インターフェイス'))¶ ↑
* HTTP * Web UI * Command line interface * API (Library)
Install - Docker¶ ↑
# coderay console % GITHUB=https://github.com % git clone \ ${GITHUB}/ranguba/chupa-text-docker.git % cd chupa-text-docker % docker-compose up --build
How to usen(('note:使い方'))¶ ↑
# coderay console % curl \ --form data=@XXX.pdf \ http://localhost:20080/extraction.json
Use casesn(('note:利用例'))¶ ↑
* Ranguba * Full text search system\n (('note:全文検索システム')) * Commit e-mail\n (('note:コミットメール'))
git-commit-mailer¶ ↑
Commit e-mail for Gitn (('note:Git用のコミットメール'))
Featuresn(('note:機能'))¶ ↑
* HTML mail\n (('note:HTMLメール')) * Highlighted diff\n (('note:diffをハイライト')) * GitLab/GitHub Web hook\n (('note:GitLab/GitHubのWebフック対応')) * (('tag:xx-small')) By ((<"GitHub:clear-code/github-web-hooks-receiver"|URL:https://github.com/clear-code/github-web-hooks-receiver>))
Usersn(('note:利用者'))¶ ↑
* tDiary * My products
commit-email.info¶ ↑
Commit e-mailn as an Servicen (('note:コミットメールのクラウドサービス'))
How to usen(('note:使い方'))¶ ↑
* Send a pull request to\n ((<"GitHub:kou/commit-email.info"|URL:https://github.com/kou/commit-email.info>))\n (('note:pull requestを送る')) * Register a Web hook\n (('note:Webフックを登録')) * Subscribe your mailing list\n (('note:メーリングリストを購読'))
(('note:See also ((<URL:www.commit-email.info/>))'))
Opening5n(('note:きっかけ5'))¶ ↑
Data processingn (('note:データ処理'))
csv¶ ↑
CSV parsern (('note:CSVパーサー'))
csv - Historyn(('note:歴史'))¶ ↑
* 2003: Import\n (('note:Rubyに取り込み')) * 2007: Replaced with FasterCSV\n (('note:FasterCSVで置き換え')) * 2018: I became a co-maintainer with mrkn\n (('note:mrknと一緒にメンテナーになった'))
Why?n(('note:なんで?'))¶ ↑
* There are many data sources\n in CSV\n (('note:CSVのデータはたくさんある')) * Important to process data\n (('note:データを処理するためにCSVパーサーは重要'))
CSV format problemsn(('note:CSVフォーマットの問題'))¶ ↑
* Slow to parse\n (('note:パースが遅い')) * Too wild\n (('note:なんでもあり'))
Red Arrow¶ ↑
Apache Arrow Ruby
Red Arrow - Historyn(('note:歴史'))¶ ↑
* 2017-02: The first commit\n (('note:最初のコミット')) * 2018-05: Became the "official" Ruby bindings of Apache Arrow\n (('note:Apache Arrowの公式Rubyバインディングになった'))
Apache Arrow¶ ↑
* Super fast data format\n (('note:すごく速いデータフォーマット')) * For in-memory data\n (('note:インメモリーデータ用')) * Cross-language support\n (('note:いろんな言語がサポート')) * Easy to share data with Python, Java, ...\n (('note:PythonやJavaなどとデータ交換がしやすい'))
Performance(('note:(性能)'))¶ ↑
# image # src = images/csv-arrow.pdf # relative_width = 100
Slide properties¶ ↑
: enable-title-on-image
false
Apache Arrow - Positionn(('note:立ち位置'))¶ ↑
* A very important piece\n in recent data processing\n (('note:最近のデータ処理界隈ではすごく大事な1ピース')) * Like JIT for Ruby 3\n (('note:Ruby 3で例えるとJITみたいな感じ'))
Red Arrow - Impl.n(('note:実装'))¶ ↑
* Based on Ruby/GI\n (('note:Ruby/GIを使っている')) * Auto generated bindings\n (('note:バインディングを自動生成'))
Extendable load APIn(('note:拡張可能なロードAPI'))¶ ↑
# coderay ruby # Load Apache Arrow data Arrow::Table.load("iris.arrow") # Load CSV data Arrow::Table.load("iris.csv") # Load Apache Parquet data Arrow::Table.load("iris.parquet")
Apache Parquet¶ ↑
* Super fast data format\n (('note:すごく速いデータフォーマット')) * For storing analysis target data\n (('note:解析対象のデータを保存する用')) * Widely used\n (('note:広く使われている'))
Performance(('note:(性能)'))¶ ↑
# image # src = images/csv-arrow-parquet.pdf # relative_width = 100
Slide properties¶ ↑
: enable-title-on-image
false
Red Parquet¶ ↑
Apache Parquet
Red Data Tools¶ ↑
A project to make Ruby data processablen (('note:Rubyでデータ処理できるようにするためのプロジェクト'))
Red Data Tools - Historyn(('note:歴史'))¶ ↑
* 2017-02: Start(('note:(開始)')) * 2017-11-: Develop events per month at Tokyo\n (('note:東京で毎月開発イベントを開催'))
The number of productsn(('note:プロダクト数'))¶ ↑
About 20n (('note:including Red Arrow and Red Parquet'))n (('note:20くらい'))n (('note:Red ArrowやRed ParquetもRed Data Toolsプロダクツ'))
Red Datasets¶ ↑
Dataset fetchern (('note:データセット取得'))
Supported datasetsn(('note:対応データセット'))¶ ↑
* Iris * CIFAR * Wikipedia
Wikipedia¶ ↑
# coderay ruby require "datasets" wikipedia = Datasets::Wikipedia.new wikipedia.each do |page| p page.title end
Wikipedia search¶ ↑
# coderay ruby pages = Groonga["pages"] wikipedia = Datasets::Wikipedia.new wikipedia.each do |page| pages.add(title: page.title, content: page.revision.text) end ruby_pages = pages.select do |record| record.match("Ruby OR Rails") do |target| (target.title * 10) | target.content end end p ruby_pages.size
jekyll-jupyter-notebook¶ ↑
Jekylln (('+'))n Jupyter Notebook
Usagen(('note:使い方'))¶ ↑
{% jupyter_notebook sample.ipynb %}
Red OpenCV¶ ↑
Computer visionn (('note:コンピュータービジョン'))
Camera(('note:(カメラ)'))¶ ↑
# coderay ruby require "cv" camera = CV::Camera.new image = camera.read image.write("capture.jpg")
Face detect(('note:(顔認識)'))¶ ↑
# coderay ruby image_gray = image.convert_color(:bgr2gray) classifier = # Face detector CV::CascadeClassifier.new("frontalface_alt") objects = classifier.detect(image_gray) color = CV::Color.new(0, 0, 255) objects.each do |object| # Draw detected area image.draw_rectangle(object, color) end image.write("detect.jpg")
Red OpenCV - Impl.n(('note:実装'))¶ ↑
* Based on Ruby/GI\n (('note:Ruby/GIを使っている')) * Auto generated bindings\n (('note:バインディングを自動生成'))
Ad: RubyData Workshop¶ ↑
* 2018-06-01 15:50/17:20 * Contents:(('note:(内容)')) * Workshop by mrkn\n (('note:mrknによるワークショップ')) * Presentations from\n Red Data Tools members\n (('note:Red Data ToolsメンバーによるRed Data Toolsでやってきたことの紹介'))
Process data with Rubyn(('note:Rubyでデータ処理'))¶ ↑
* We're working on it\n (('note:Red Data Toolsは継続して取り組んでいる')) * Do you want to work with us?\n (('note:一緒にやりたい人はいる?'))
How to join1(('note:(参加方法1)'))¶ ↑
* Join our chat rooms:\n (('note:チャットルームに参加')) * en: ((<"Gitter:red-data-tools/en"|URL:https://gitter.im/red-data-tools/en>)) * ja: ((<"Gitter:red-data-tools/ja"|URL:https://gitter.im/red-data-tools/ja>)) * Join monthly events at Tokyo\n (('note:東京での毎月の開発イベントに参加')) * ((<URL:https://speee.connpass.com/>))
How to join2(('note:(参加方法2)'))¶ ↑
* Hire developers to work on it\n (('note:仕事として開発する開発者を雇う')) * e.g.: mrkn by Speee, Inc.\n (('note:例:Speeeの村田さん'))
How to join3(('note:(参加方法3)'))¶ ↑
* Order ClearCode to work on it\n (('note:クリアコードに開発の仕事を発注')) * Join ClearCode to work on it\n (('note:クリアコードに入って仕事として開発を進める'))
Wrap upn(('note:まとめ'))¶ ↑
* I'm working on the following as a Rubyist\n (('note:Rubyistとしての私の活動')) * Increase what Ruby can do\n with free software\n (('note:フリーソフトウェアを使ってRubyでできることを増やす')) * Maintain libraries\n (('note:ライブラリーのメンテナス')) * Do you want to work with me?\n (('note:一緒にやりたい人はいる?'))