Interface

: 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:40: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

Interface?

A | B
  ^
 Here

API

Library | Program
        ^
       API

Web API

Server | HTTP | Client
       ^^^^^^^^
       Web API

CLI

Program | command | User
        ^^^^^^^^^^^
  Command Line Interface

My activitiesnas a Rubyist

* Expand "Ruby ready" areas
* Maintain libraries

The number of developing libraries

About 130

Ruby anywhere

There are many interfaces

This talk's content

* Show my knowledge\n
  from my activities\n
  (('note:自分の活動で得られた知見を紹介'))
* Perspective:"Interface"\n
  (('note:切り口:「インターフェイス」'))

RSS Parser

Makes Rubyn ((*Web feed*))n ready

RSS Parser - History

* 2003-05: The first release
* 2004-01: Ruby bundles this
  * Became a Ruby committer

RSS Parser - Interface

RSS Parser | Programmers
           ^
          API

RSS Parser - API

* Map RSS structure to
  * classes and
  * methods

Map to classes

<rss>                    RSS::Rss
  <channel>              RSS::Rss::Channel
    <title>...</title>   String
    <item>               RSS::Rss::Channel::Item
      <title>...</title> String
    <item>
    <item>               RSS::Rss::Channel::Item
      <title>...</title> String
    <item>
  </channel>
</rss>

Map to methods

<rss>                    rss
  <channel>              rss.channel
    <title>...</title>   rss.channel.title
    <item>               rss.channel.items[0]
      <title>...</title> rss.channel.items[0].title
    <item>
    <item>               rss.channel.items[1]
      <title>...</title> rss.channel.items[1].title
    <item>
  </channel>
</rss>

Pros

Users can guess API from their data

Example

<rss>                    # Want /rss/channel/item/title!
  <channel>              rss.channel.items.each do |item|
    <title>...</title>
    <item>
HERE: <title>...</title>   p item.title
    <item>
    <item>
HERE: <title>...</title>
    <item>
  </channel>             end
</rss>

Cons

Verbosen for expert

Cons - Interface

RSS Parser | Not experts
         Good

RSS Parser | Experts
        Verbose

Example

<rss>                    # Want item/title!
  <channel>              # Don't want to care
    <title>...</title>   # about channel.
    <item>               rss.items.each do |item|
HERE: <title>...</title>   p item.title
    <item>
    <item>
HERE: <title>...</title>
    <item>               end
  </channel>
</rss>

Cons

Not generic

Web feed types

* RSS 0.9*/2.0
  * Really Simple Syndication
* RSS 1.0
  * RDF Site Summary
* Atom
  * RFC 4287

Differences

They are ((NOT)) compatible

Differences - Interface

RSS Parser | RSS 0.9*/2.0
RSS Parser | RSS 1.0
RSS Parser | Atom
           ^
  Different structures

What users want

Processn all feed typesn in the same way

+ High level API

# coderay ruby
# RSS 0.9*/20
rss.items # /rss/channel/item
# RSS 1.0
rdf.items # /RDF/item
# Atom
feed.items # /feed/entry

+ High level API

Users | RSS Parser | RSS 0.9*/2.0
Users | RSS Parser | RSS 1.0
Users | RSS Parser | Atom
      ^            ^
 Common API  Different structures

RSS Parser - Design

* Premise:(('note:前提:'))
  * Users can confirm their data\n
    (('note:ユーザーは自分たちのデータを確認できる'))
* Easy to use:(('note:使いやすくするために:'))
  * Map data structure to Ruby\n
    (('note:データの構造をそのままRubyの世界に対応させる'))
  * + common feed type aware API\n
    (('note:さらにフィードの種類に依存しない共通APIも用意'))

Knowledge - RSS Parser

* Premise is important for API\n
  (('note:API設計に前提は大事'))
* Different API layer for\n
  different type users\n
  (('note:違う種類のユーザーには違うAPIのレイヤーを'))

RSS Parser - Omit

Validationn isn important

Rabbit

Makes Rubyn ((presentation))n ready

Rabbit - History

* 2004-07: The first release
* 2010: Matz starts using Rabbit
  * Since RubyKaigi 2010?

Rabbit - Pitch

(('tag:center')) (('tag:large')) A presentation tooln for ((Rubyist))

((' '))

Rabbit - Run

# coderay console
% rake

Run - Interface

Rabbit | rake | Rubyist
       ^^^^^^^^
    CLI for Rubyist

Rabbit - Publish

# coderay console
% rake publish:rubygems

publish:rubygems

# coderay console
% rake gem
Generates pkg/XXX.gem
% gem push pkg/XXX.gem

Rabbit Slide Show

# img
# src = images/rabbit-slide-show.png
# relative_height = 78

(('tag:center')) (('tag:small')) ((<URL:slide.rabbit-shocker.org/>))

Slide properties

: enable-title-on-image

false

Publish - Interface

Rabbit | gem push | Rubyist
       ^^^^^^^^^^^^
   Like a normal library
      No Web browser
 Your slides are versioned

Slide as a Gem

# coderay console
% rake gem
% gem unpack pkg/*.gem
% tree rabbit-slide*

PDF in gem

# coderay console
% tree rabbit-slide*
├── README.rd
...
├── pdf
│   └── rubykaigi-2018-interface.pdf
...

Publish PDF in gem

(1) Receive published notifications from rubygems.org
(2) Render PDF in gems for Web browser

(('tag:center')) (('tag:xx-small')) ((<URL:github.com/rabbit-shocker/slide.rabbit-shocker.org>))

Receive notifications

# coderay console
% curl \
    -H 'Authorization:...' \
    -F 'gem_name=*' \
    -F 'url=https://slide.rabbit-shocker.org/web-hook-receiver/' \
    https://rubygems.org/api/v1/web_hooks

(('tag:center')) (('tag:xx-small')) ((<URL:guides.rubygems.org/rubygems-org-api/#webhook-methods>))

Notification - Interface

slide.rabbit-shocker.org | RubyGems.org
                         ^
                      Web hook

Render PDF

Combine the following gems

* poppler - PDF parser
* cairo - 2D graphics library

poppler & cairo

Makes Rubyn ((PDF))n ready

poppler - History

* 2006-07: The first release
* 2018-05: The latest release

poppler - Parse

# coderay ruby
pdf = Poppler::Document.new(content)
pdf.each do |page|
  # Convert each page to PNG
end

poppler - Interface

poppler |  path | PDF
poppler |content| PDF
        ^^^^^^^^^
          Input

cairo - History

* 2003-10: The initial commit
* 2005-09: I started developing
  * Sent several patches and\n
    got commit bit and more
* 2005-10: The first release
* 2018-05: The latest release

cairo - Outputs

((PNG)), PDF, SVG, X, Quarts, Win32, …

(('tag:xx-small')) See also: More about cairo gem in Japanesen ((<URL:magazine.rubyist.net/articles/0019/0019-cairo.html>))

cairo - To PNG

# coderay ruby
iw, ih = image_width, image_height
Cairo::ImageSurface.new(iw, ih) do |surface|
  Cairo::Context.new(surface) do |context|
    width, height = page.size
    x_scale = iw / width.to_f
    y_scale = ih / height.to_f
    context.scale(x_scale, y_scale)
    context.render_poppler_page(page) # Render
    surface.write_to_png("XXX.png")   # Save
  end
end

cairo - Interface

cairo |Poppler::Page| PNG
      ^^^^^^^^^^^^^^^
          Input

PDF on the Web - Link

# img
# src = images/pdf-clickable.png
# relative_height = 100
# reflect_ratio = 0.05

Slide properties

: enable-title-on-image

false

Link in image in HTML

# coderay html
<map id="XXX">
  <area href="..."
        shape="rect"
        coords="X,Y,W,H">
</map>
<img usemap="#XXX">

poppler - coords

# coderay ruby
pdf.each do |page|
  page.link_mapping.each do |mapping|
    href = mapping.action
    x, y, w, h = mapping.area.to_a
    coords = "#{x},#{y},#{w},#{h}"
    # Generate <area>
  end
end

Link - Interface

PDF |poppler| HTML
    ^^^^^^^^^
Extract information

Rabbit - Input

* Source
  * RD (Ruby Document), Markdown(('note:, PDF, image, ...'))
* Theme
  * Ruby scripts

Input - Interface

Rabbit |texts| Rubyist
       ^^^^^^^
 Version controllable
 Like normal programs

Knowledge - Rabbit

* Pitch is important for interface\n
  (('note:インターフェイス設計にピッチは大事'))
  * "for ((*Rubyist*))" for Rabbit
* Use similar way for the original

Rabbit - Theme

Define viewn by Rubyn (('note:Rubyで見た目を定義'))

Theme - Layers

* Customize parameters
* Normal Ruby codes to\n
  control render something

Theme - Parameters

# coderay ruby
# CSS selector inspired API:
#   title-slide author {
#     margin_top: 2px;
#     margin_bottom: 1px;
#   }
match(TitleSlide, Author) do |authors|
  authors.margin_top = @space * 2
  authors.margin_bottom = @space
end

Theme - Render

# coderay ruby
match(Slide) do |slides|
  loader = ImageLoader.new("mini-kame-taro.png")
  slides.add_post_draw_proc do
    x = ... # Compute the next tortoise position
    loader.draw(canvas, x, y, parameters)
  end
end

(('note:The')) Tortoise and (('note:the')) Harenin Rabbitn(('note:Rabbitでうさぎとかめ'))

# img
# src = images/the-tortoise-and-the-hare.png
# relative_width = 100
# reflect_ratio = 0.05

Slide properties

: enable-title-on-image

false

Hare - Slide positionn(('note:うさぎはスライド位置'))

# img
# src = images/the-tortoise-and-the-hare-hare.png
# relative_width = 100
# reflect_ratio = 0.05

Slide properties

: enable-title-on-image

false

Tortoise - Timern(('note:かめはタイマー'))

# img
# src = images/the-tortoise-and-the-hare-tortoise.png
# relative_width = 100
# reflect_ratio = 0.05

Slide properties

: enable-title-on-image

false

Slown(('note:遅い'))

# img
# src = images/the-tortoise-and-the-hare-slow.png
# relative_width = 100
# reflect_ratio = 0.05

Slide properties

: enable-title-on-image

false

Goodn(('note:ちょうどいい'))

# img
# src = images/the-tortoise-and-the-hare-good.png
# relative_width = 100
# reflect_ratio = 0.05

Slide properties

: enable-title-on-image

false

Fastn(('note:速い'))

# img
# src = images/the-tortoise-and-the-hare-fast.png
# relative_width = 100
# reflect_ratio = 0.05

Slide properties

: enable-title-on-image

false

Knowledge - Rabbit

* Product name is important for interface\n
  (('note:インターフェイス設計にピッチは大事'))
  * Rabbit isn't Hare😜
* ...

TODO

i18n

Jekyll

rake only

twitter.com/darashi/status/909994900694769664

gdb b rb_raise