Rabbit Slide Show

Build your own tools

Description

Now FLOSS is so common that even Microsoft use it and develop it. But do you have control over your tools for daily use? Building your own tools is the best way to develop software, and Ruby is the best language for such use. In this talk, I introduce my own tools and my development style.

Text

Page: 1

Build your own
tools
Shugo Maeda
Network Applied Communication
Laboratory Ltd.
2018-06-02

Page: 2

Self introduction
Shugo Maeda
Ruby committer
Secretary General at Ruby
Association
Director at Network Applied
Communication Laboratory
Ltd. (NaCl)

Page: 3

Proposed features
protected
callcc
Refinements
puts

Page: 4

Ruby Association
Foundation dedicated to Ruby
Maintenance of the stable version of
Ruby
Grant
Conferences and Seminars
Case studies at www.ruby.or.jp
Examination

Page: 5

[ANN] Grant report
Date: 2018-07-07
Venue: Shinagawa, Tokyo
Speakers: Matz, Naotoshi Seo,
Uchio Kondo, Takashi Kokubun
https://
rubyassociation.doorkeeper.jp/
events/74355

Page: 6

[ANN] RubyWorld
Conference
Date: 2018-11-01 〜
2018-11-02
Venue: Matsue, Shimane
Keynote Speakers: Matz, Chad
Fowler
http://www.rubyworld-conf.org

Page: 7

NaCl
Commissioned development of
Web (and other) applications
Foucused on FLOSS
Matz belongs to NaCl since
1997
Head office in Shimane /
Branch office in Tokyo

Page: 8

FLOSS
Free/Libre and Open Source
Software

Page: 9

Free software
Free as in beer
Free as in speech
自由ソフトウェア
Social movement

Page: 10

Open source software
Open Source Definition
Published by the Open Source
Initiative
Based on Debian Free Software
Guidelines
Development methodology

Page: 11

Microsoft
Joined the Linux Foundation
https://www.linuxfoundation.org/
press-release/microsoft-fortifies-
commitment-to-open-source-
becomes-linux-foundation-platinum-
member/
Joined the Open Source
Initiative
https://opensource.org/node/901

Page: 12

Did FLOSS win?

Page: 13

Web applications
Everyone use them
FLOSS used often
Linux, GNU toolchain, Apache, Ruby,
Rails…

Page: 14

I hate Web applications

Page: 15

I hate
Gmail
Google Docs, Sheets, and
Slides
Cloud9

Page: 16

These are OK
tDiary
Redmine
Amazon (shopping site)
Netflix

Page: 17

What is common to these?

Page: 18

SaaSS
≠ SaaS (Software as a Service)
Service as a Software Substitute
https://www.gnu.org/philosophy/
who-does-that-server-really-
serve.html
Services for your computing

Page: 19

Non SaaSS
FLOSS
tDiary
Redmine
Not for your computing
Amazon
Netflix

Page: 20

Take back control over
your computing

Page: 21

Build your own tools

Page: 22

Why?
You can’t always get what you
want
Serve yourself
For fun

Page: 23

Why Ruby?
Availability
Productivity
Text handling power
Ecosystem
Fun

Page: 24

My own tools

Page: 25

Keyboard

Page: 26

Viterbi
Split Ortholinear keyboard kit
Available at https://keeb.io

Page: 27

Hard to fix hardware

Page: 28

Free keyboard

Page: 29

QMK Firmware
Open source firmware for AVR
and ARM based keyboards
Lincensed under GPL

Page: 30

T-Code Keyboard
T-Code
Direct Kanji Input
No Kana-to-Kanji conversion
Kanji composition
e.g. 五 + 口 = 吾
Implemented on QMK Firmware

Page: 31

No Ruby Inside
Max firmware size: 28KB
Even mruby/c is too large
Written in C
http://nacl-
ltd.github.io/2018/01/23/
japanese-input-by-qmk.html

Page: 32

Table generation
require_relative "tc_tbl"
puts "/* Generated by gentbl.rb; DO NOT EDIT! */"
puts "const uint16_t PROGMEM tcode_table[] = {\n"
TC_TBL.flat_map { |row|
row.gsub(" ", "").each_char.map { |ch|
"0x%04X" % ch.ord
}
}.each_slice(8) do |cs|
puts " " + cs.join(", ") + ","
end
puts "};\n"

Page: 33

Generated table
* Generated by gentbl.rb; DO NOT EDIT! */
const uint16_t PROGMEM tcode_table[] = {
0x25A0, 0x25A0, 0x25A0, 0x25A0, 0x25A0,
0x25A0, 0x25A0, 0x30EE, 0x30F0, 0x30F1,
0x5883, 0x7CFB, 0x63A2, 0x8C61, 0x308E,
0x25A0, 0x76DB, 0x9769, 0x7A81, 0x6E29,
0x25A0, 0x25A0, 0x25A0, 0x4F9D, 0x7E4A,
0x25A0, 0x25A0, 0x25A0, 0x25A0, 0x25A0,
0x25A0, 0x25A0, 0x4E11, 0x81FC, 0x5BB4,
0x8CC0, 0x5CB8, 0x8CAC, 0x6F01, 0x65BC,
0x25A0, 0x76CA, 0x63F4, 0x5468, 0x57DF,
0x25A0, 0x25A0, 0x25A0, 0x7E54, 0x7236,
0x25A0, 0x25A0, 0x25A0, 0x25A0, 0x25A0,
0x25A0, 0x25A0, 0x9B3C, 0x865A, 0x72ED,
0x559C, 0x5E79, 0x4E18, 0x7CD6, 0x5947,
0x4EAB, 0x5EB7, 0x5F92, 0x666F, 0x51E6,
0x25A0, 0x25A0, 0x25A0, 0x8B72, 0x30D8,
0x25A0, 0x25A0, 0x25A0, 0x25A0, 0x25A0,
0x25A0,
0x30F5,
0x3090,
0x6355,
0x501F,
0x25A0,
0x7E01,
0x6C5A,
0x8352,
0x679A,
0x25A0,
0x8105,
0x65E2,
0x305C,
0x6A21,
0x25A0,
0x25A0,
0x30F6,
0x3091,
0x25A0,
0x9808,
0x25A0,
0x66F3,
0x4E59,
0x25A0,
0x4E71,
0x25A0,
0x9A5A,
0x83CA,
0x25A0,
0x964D,
0x25A0,
0x25A0,
0x8ACB,
0x25A0,
0x25A0,
0x8A33,
0x25A0,
0x5C1A,
0x7A4F,
0x25A0,
0x9999,
0x25A0,
0x820E,
0x5374,
0x25A0,
0x8D70,
0x25A0,

Page: 34

Small scripts

Page: 35

ftpup
Upload files via FTP
FTP was used to upload HTML
files in the past
Using Net::FTP

Page: 36

imaparchive
Move or Delete old mails on
IMAP servers
Using Net::IMAP

Page: 37

rd2sxi
Convert RD to OpenOffice
Impress slides

Page: 38

rd2latex
Convert RD to LaTeX files

Page: 39

Programming languages

Page: 40

demi
Original language for JVM
Lisp-1
No class definition
for expression
Closures
REPL (Read-Eval-Print Loop)

Page: 41

Example
frame = new Frame("Test");
frame.setLayout(new FlowLayout());
hello = new Button("Hello");
hello.addActionListener([ e:
println("Hello, World!");
]);
frame.add(hello);

Page: 42

babel
Sather Compiler for .NET
Not a JavaScript compiler

Page: 43

Sather
Statically typed object oriented
language
Separation of Subtyping and
Code Inclusion
Iterators
Closures

Page: 44

Example
abstract class $PERSON is
say;
end;
class HELLO_MIXIN is
say is
#OUT + "hello.\n";
end
end;
class PERSON < $PERSON is
include HELLO_MIXIN;
end

Page: 45

Servers

Page: 46

rskkserv
Dictionary server for SKK
SKK: Japanese Input Method
Binary search

Page: 47

ximapd
eXperimental IMAP server
Use mailbox names as search
queries

Page: 48

TUI applications

Page: 49

TUI
Text-based User Interface
Used on terminals
More rich than CUI

Page: 50

Textbringer
Emacs-like text editor
Less parentheses
Matz Lisp a.k.a. Ruby
Cool name

Page: 51

Mournmail
MUA (Message User Agent)
Textbringer plugin
Gmail like search interface
Powered by Groonga/Rroonga
Multi account support
Unstable specification

Page: 52

Groonga/Rroonga
Groonga
Full-text search engine
Rroonga
Ruby interface for Groonga

Page: 53

Good support

Page: 54

Search multiple columns
# query = "jemalloc"
# query = "from:@matz subject:@ruby"
messages = Groonga["Messages"].select { |record|
record.match(query) { |match_record|
match_record.subject | match_record.body
}
}.paginate([["date", :desc]], page: page, size: 100)

Page: 55

Demo

Page: 56

How to build tools

Page: 57

Materials
Motivation
Time
Skills

Page: 58

Feel good about yourself
Many geniuses in the world
I’m not…
But it’s OK

Page: 59

Find your favorite theme
Text editors?
Programming languages?
Graphical tools?
Machine learning?

Page: 60

Start with something easy
One liners
Small scripts

Page: 61

Examples
Mail archivers over Message
user agents
Slide generators over
Presentation tools

Page: 62

Phisical LOC
imaparchive
99
ftpup
294
rskkserv
316
Mournmail
2236
ximapd
5101
Textbringer
6526
babel
11822
demi
12205
exluding test code

Page: 63

Cut corners
Create a Minimum Viable
Product before getting bored
Reinvent the wheel only when
you want to
Inconvenience vs
Implementation cost

Page: 64

Examples in programming
languages
Use existing virtual machines
Use existing libraries

Page: 65

Examples in text editors
ASCII support only at first
Text User Interface
Redisplay by curses

Page: 66

Postpone test writing
You don’t know what you want
at first
Use it everyday instead
Test code should help changes

Page: 67

Specification bugs
What’s wrong in the following
code?
def move_mail(src_mailbox, uid, dst_mailbox)
src_path = Mournmail.mail_cache_path(src_mailbox, uid)
dst_path = Mournmail.mail_cache_path(dst_mailbox, uid)
begin
File.rename(src_path, dst_path)
rescue Errno::ENOENT
end

Page: 68

UID is mailbox local
UID is changed after COPY
Change cache paths
Old: mailbox/uid
New: 00-ff/hash

Page: 69

Take risks
eval
monkey patching
refinements
callcc

Page: 70

Protect your data
Leave mails on the IMAP server
Dump unsaved files on crash
Backup / Use VCS for
important data

Page: 71

Make it extensible
Small core with extensions
Emacs = Editor MACroS

Page: 72

Emacs vs vi
Key bindings don’t matter
Extensible or not?
Vim is an Emacs-type editor

Page: 73

Extension languages
Host
Extension
language language
GNU
C
Emacs
Emacs
Lisp
Vim
C
Vim
script
Textbring Ruby
Ruby
er

Page: 74

Ruby
Suitable for extensions
Dynamic
Brief notation

Page: 75

Customization
def load_user_config
config_file = File.expand_path("~/.textbringer.rb")
begin
load(config_file)
rescue LoadError
end
end

Page: 76

~/.textbringer.rb
CONFIG[:east_asian_ambiguous_width] = 2
Buffer.detect_encoding_proc = Buffer::NKF_DETECT_ENCODING
Face.define :mode_line, foreground: "#ffffff", background: "#75507b"
add_hook :c_mode_hook, -> {
buf = Buffer.current
if buf.file_name &&
File.dirname(buf.file_name).end_with?("/ruby")
buf[:indent_level] = 4
buf[:tab_width] = 8
buf[:indent_tabs_mode] = true
buf[:c_continued_statement_offset] = 4
buf[:c_case_label_offset] = -2
buf[:c_label_offset] = -2
end
}

Page: 77

Plugins
Load files in ~/.textbringer/
plugins
Packaging system
RubyGems

Page: 78

Gem.find_latest_files
def self.load_plugins
files = Gem.find_latest_files("textbringer_plugin.rb", false) +
Dir.glob(File.join(directory, "*/**/textbringer_plugin.rb"))
files.each do |file|
begin
load(file)
rescue Exception => e
show_exception(e)
end
end
end

Page: 79

Interactive programming
Change behavior of object at
runtime
load, eval, open classes
REPL
Examples in Textbringer
eval_buffer, eval_region,
eval_expression

Page: 80

Unreloadable code
module Mournmail
@current_mailbox = nil

Page: 81

Keep states on reload
module Mournmail
def self.define_variable(name, initial_value: nil,
attr: nil)
var_name = "@" + name.to_s
if !instance_variable_defined?(var_name)
instance_variable_set(var_name, initial_value)
end
...
end
define_variable :current_mailbox, attr: :accessor

Page: 82

Local monkey patching
module FillExtension
refine Buffer do
def fill_region(s, e)
...
end
end
end
module Commands
using FillExtension
define_command(:fill_region) do
|s = Buffer.current.point, e = Buffer.current.mark|
Buffer.current.fill_region(s, e)
end
end

Page: 83

Internal DSLs
Declarative
Too much DSLs decrease
readability as Ruby code

Page: 84

Parser combinator
using RaddDjur::DSL
grammar = RaddDjur::Grammar.new(:additive) {
# additive ← multitive '+' additive / multitive
define :additive do
:multitive.bind { |x|
"+".bind {
:additive.bind { |y|
ret x + y
}
}
} / :multitive
end

Page: 85

Bootstrapping
Self-compiling compiler
C → Language X → Language X
Self-editing text editor
Vim → Textbringer → Textbringer

Page: 86

After finished

Page: 87

Osusowake
Japanese word meaning sharing
Share meals when cooked too much
Software never decrease
Share your software as FLOSS

Page: 88

Summary
Take back control over your
computing
Build your own tools by Ruby
Share your tools as FLOSS

Other slides