「初めてのRuby」をRubyPicoで実際に動かしながら読む

RubyPico向けの入門記事を書きたくて、Rubyの入門書を改めて色々と読み直している。まずはずっと気になっていた「初めてのRuby」を購入。

初めてのRuby

初めてのRuby

pdfはHonyomiに突っ込んだのでいつでも検索できるようになった。こういう振り返り記事を書くときはとても役に立つ。

f:id:tuto0621:20160815214402j:plain

今回初の試みとして

  • iPadでpdfを表示 (こっちは紙の書籍でもKindleでもよい)
  • iPod touchでRubyPicoを実行

させてサンプルコードを実行しながら読み進めた。今申請中の0.8からはmain不要でスクリプトを書けるようになり、大分CRubyと同じ雰囲気で書けるようになったからだ。例えば書籍内で紹介されていた素数か判定する以下のプログラムはそのままRubyPicoで実行することができた。

(2..100).each do |candidate|
  sqrt = Math.sqrt(candidate)
  factor_found = (2..sqrt).any? {|i| candidate % i == 0}
  if factor_found then
    print "#{candidate} は合成数\n"
  else
    print "#{candidate} は素数\n"
  end
end

実際にコードを打ち込んで挙動を確認しながら読み進めると理解が一段深くなる。ifにはthenをつけない、{|i| }{ |i| }派、みたいな自分のスタイルに置き換えても同じように動くことを確認していけるのもよい。

f:id:tuto0621:20160815214622p:plain

書籍自身の感想としては、RubyコミッタのYuguiさんが書いただけあってRubyの深いところまで理解した上でRuby初心者(この書籍は他言語を習得しているけどRubyを初めて使う人を対象に書かれている)向けの内容が厳選されており大変読みやすい。私は割と必要なスクリプトを書くために実践的にRubyを覚えてしまったところがあるので、基礎的な知識がポッカリ抜けている部分がありそれらを補完することができた。String#[regexp]とかString#%とか知らなかったけどこれからは積極的に使っていこうと思う。私が使い慣れているC++C#などの静的言語と比較しながら説明してくれるのもわかりやすかった。

特に面白かったのは7章のメソッドと8章のオブジェクトとクラスで、なんとなく使っていたブロック付きメソッドとProc型の違いブロックを引数として受け取る方法などがすごく短いページに(ここ重要)簡潔にまとめられていて大変よかった。8章などRubyの強力なメタ機能をささえるクラス、オブジェクト、特異、モジュールといったコア要素の一通りの説明がたった22Pに収められていて必要に応じてまた読み返したいと思う。あとモジュールの説明で2つの目的があってMix-in(これはよく見かける)と名前空間の提供(これ割と見かけない)というのをちゃんと章を分けて説明してくれていて大変安心した。他の人のコード読んだりすればモジュールを名前空間として使ってよいのはなんとなく分かるのだけどそれを章立てして説明してくれているのは初めてみたので(多分書いてあるのだけど私が今まで見落としていた)。

と、いう訳ですでにRubyに慣れている人でも「初めてのRuby」は大変おすすめです。短いページ数に必要な情報が凝縮されているのでさっと読んだ後に必要に応じて簡単に読み返せるのもよいです。

※ 余談ですが最近はたくさんの情報が網羅されてページ数の多い本よりも必要な情報が短いページに凝縮された本の方を好むようになってきました

夏休みの宿題でRubyPicoを再開

思ったことを最速でブログに書く環境もだいぶ整備できたのでRubyPicoの開発に戻る。まずは夏休みを使ってmain無しで動く最新のRubyPicoをリリースしたい。そのあとで書きかけのスマホではじめるRubyプログラミングを書く。プログラミングを学びたい人がRubyだけで色々なものを作れるようにしていく予定。

雑記: 洋書の読み方

Create Your Own Programming Languageを紹介したときに洋書読むの大変そうという話をよく聞いたので自分が使った教材を紹介する記事を書き始めた、が以外と長くなっているのでもう一息。端的に言うと

  • 「英語じゃないと読めないけどどうしても読みたい文章」を頑張って見つける
  • 基本からわかる英語リーディング教本
  • English Grammar in Use Book
  • 英単語アプリ mikan

みたいな感じです。

自分でプログラム言語を書いてみたい人は「Create Your Own Programming Language」がおすすめ

読み終わった。たった100Pにプログラム言語を作るための基礎(字句解析、構文解析、ランタイム、インタプリタ仮想マシン、ネイティブコンパイルまで!)が一通り学べ、さらに本書で作った実際に動くプログラミング言語がついてくる。 $39.99 とちょっと高いがプログラム言語を作る勉強代だと考えれば最も安くそして早く(ドラゴンブックは1090P)学べるのではないだろうか。洋書なのが難点だが半分くらいはソースコードなので苦労しながらなんとかなりました。(日本語訳出てほしいなぁ)

書籍内で作る言語は2種類で

  • Awesome
    • Rubyの構文にPythonのインデントブロックを混ぜ合わせたようなオブジェクト型
  • Mio
    • Ioを参考にしたメッセージ型

言語自体はどちらもRubyで書かれているが紹介される概念は特に言語の制約を受けないものが多い。

よかったところ

yaccやbison, JVM系の構文解析ツールなど実際に言語開発者によく使われているツール群の紹介が前半にたくさんあったのがよかった。この手のツールはあまりインターネットを漫然とサーフィンしているだけだとなかなか知る機会がないため。

「6. Runtime Model」の章。ものすごい数のプログラミング言語があるけどランタイムモデルの数はそこまで多くないということが分かった。これらと字句解析、構文解析の組み合わせで様々な言語が生まれる。(もちろん実際の言語はもう少し複雑でプロトタイプ型の特徴をもったクラス型、みたいな感じにいいとこどりだったりすると思うけど。)

  1. Procedural (手続き型、Cとか)
  2. Class-based (クラス型、Ruby, Python, C++, Javaとか、今だと一番多い?)
  3. Prototype-based (プロトタイプ型、JavaScript、実装がとてもシンプルに書けるのが特徴)
  4. Functional (関数型、Haskell, Lisp)

プログラム言語ってそれぞれ全然違うように見えて内部の実装の基礎的なところはかなり同じ概念で作られていることが多いので、プログラム言語を作ることに興味がない人でも、どんな基礎概念をベースに作られているのか、これらをたたき台に次はどんな言語が生まれるのか?と言ったことが分かるようになるのでおすすめです。

おまけ

こんなところにもmatzパワーが。

f:id:tuto0621:20160804002429p:plain

さらにこの本を読んで感動した Jeremy Ashkenas さんが書籍内のサンプル言語をたたき台に作った言語が CoffeeScript だというのだからすごい。(たしかに Awesome と CoffeeScript はちょっと似ているところがある。)

追記

書籍内では字句解析(lex)の部分はRuby正規表現を使って自前で作成、構文解析(yacc)の部分はRacc(Rubyで書かれたyacc)を使ってやっています。ツールのインストールにつまずきにくいのでよいですね。

この本を購入するには、著者のページのあのフォームにクレジットカード番号を入力して購入するしかないでしょうか? (少々、不安なフォームに見えるので・・・)

PayPalのアカウント作ってそこから購入するのがおすすめです。海外で買い物するならPayPalは作っておいて損はないと思います。

ファイル内のidの有無で新規か更新かを自動で判別できるように

ちょっとずつ自分好みの改善を加えていく。

使い方

新規作成

$ hw 001.md
http://ongaeshi.hatenablog.com/entry/2016/08/03/002228 (New)

更新

$ hw 001.md
http://ongaeshi.hatenablog.com/entry/2016/08/03/002228

記事を書き換えていくだけなら特にオプションも気にせずに実行すればよいということです。

これももう少し使ってみてよさそうだったらMRに出してみようかな。

hatenablog gemでタグ付きの文章が出力できない問題を解決した

色々とコード書き換えながら試したいのでローカルにbundle installする。

$ bundle install --path vendor/bundle

これでvendor/bundle以下にあるgemファイルを書き換えることでライブラリの挙動を変えたりpしながら調べることができる。

コードを読んでいくとxmlにエスケープが入っていないことが分かった。rubyでシンプルなXML escape。なので以下のようにエンコード関数を渡すことで動くようになった。

def entry_xml(title = '', content = '', categories = [], draft = 'no', updated = '', author_name = @user_id)
  .
  .
  xml % [e(title), author_name, e(content), updated, categories_tag, draft]
end

足したe()関数はこんな感じ。

def e(str)
  str.encode(xml: :text)
end

うまく行ったぜー、とプルリクエスト送ろうと思ったらkymmt90/hatenablogにあるコードと中身が違う、あれ?よくみるとbundle installで入っているのはhatenablog-0.2.1だけど最新はhatenablog-0.2.2であることに気がついた。これはもしかして・・・結局マージリクエストは以下のようになった。

Update hatenablog to 0.2.2 by ongaeshi · Pull Request #2 · kymmt90/hatenablog-writer

これで以下のようなタグ付きのテキストも問題なく投稿できるようになった。

<html>
</html>

hatenablog gemでタグ付きの文章が出力できない問題を解決した

色々とコード書き換えながら試したいのでローカルにbundle installする。

$ bundle install --path vendor/bundle

これでvendor/bundle以下にあるgemファイルを書き換えることでライブラリの挙動を変えたりpしながら調べることができる。

コードを読んでいくとxmlにエスケープが入っていないことが分かった。rubyでシンプルなXML escape。なので以下のようにエンコード関数を渡すことで動くようになった。

    def entry_xml(title = '', content = '', categories = [], draft = 'no', updated = '', author_name = @user_id)
      .
      .
      xml % [e(title), author_name, e(content), updated, categories_tag, draft]
    end

足したe()関数はこんな感じ。

    def e(str)
      str.encode(xml: :text)
    end

うまく行ったぜー、とプルリクエスト送ろうと思ったらkymmt90/hatenablogにあるコードと中身が違う、あれ?よくみるとbundle installで入っているのはhatenablog-0.2.1だけど最新はhatenablog-0.2.2であることに気がついた。これはもしかして・・・結局マージリクエストは以下のようになった。

Update hatenablog to 0.2.2 by ongaeshi · Pull Request #2 · kymmt90/hatenablog-writer

これで以下のようにタグ付きの文章でも問題なく投稿できるようになった。 :smile:

<html>
</html>

はてなブログをコマンドラインから投稿できるようにした

この記事がすでにコマンドラインで投稿している。 hateblog-writeというのをインストールしてみた。

インストール

はてなブログ API 用の gem を書いた - blog.kymmt.comに沿ってコンシューマキー、アクセストークンの順に取得、config.ymlを生成すればよい。

落とし穴1 権限

read_private, write_private はデフォルトOFFなので注意。全ての権限を有効にしておくこと。

$ get_access_token CONSUMER_KEY CONSUMER_SECRET
/opt/local/lib/ruby2.3/gems/2.3.0/gems/oauth-0.4.7/lib/oauth/consumer.rb:178:in `request': parameter_rejected (OAuth::Problem)
    from /opt/local/lib/ruby2.3/gems/2.3.0/gems/oauth-0.4.7/lib/oauth/consumer.rb:194:in `token_request'
    from /opt/local/lib/ruby2.3/gems/2.3.0/gems/oauth-0.4.7/lib/oauth/consumer.rb:136:in `get_request_token'
    from /opt/local/lib/ruby2.3/gems/2.3.0/gems/hatenablog-0.2.2/exe/get_access_token:26:in `get_request_token'
    from /opt/local/lib/ruby2.3/gems/2.3.0/gems/hatenablog-0.2.2/exe/get_access_token:50:in `get_access_token'
    from /opt/local/lib/ruby2.3/gems/2.3.0/gems/hatenablog-0.2.2/exe/get_access_token:60:in `<top (required)>'
    from /opt/local/bin/get_access_token:23:in `load'
    from /opt/local/bin/get_access_token:23:in `<main>'

落とし穴2 config.yml

うまくいかないときは大抵の場合config.ymlの設定をミスっている。はてなブログIDはドメインを指定する。私だったらongaeshi.hatenablog.comとか。

consumer_key: <コンシューマキー>
consumer_secret: <コンシューマシークレット>
access_token: <アクセストークン>
access_token_secret: <アクセストークンシークレット>
user_id: <ユーザ ID>
blog_id: <はてなブログ ID>
.
.
.
blog_id: ongaeshi.hatenablog.com

落とし穴3 ロケール

ロケールを設定しておかないと日本語を含むマークダウンを投稿できないので注意。以下を~/.profile~/.bashrcに設定。

export LC_ALL=ja_JP.UTF-8
export LANG=ja_JP.UTF-8

使い方

$ cd ~/Documents/hatenablog-writer
$ cat blog/001/md
Test

This is test

投稿

$ bundle exec hw -c diary blog/001.md

更新

$ bundle exec hw -u blog/001.md

改造

hatenablog-writer/hw に以下のコードを足すと更新後に記事のURLを出力してくれて幸せになれます。

HBWriter.new do |hb_writer|
  ARGV.each do |file_name|
    entry_text = ''
    open(file_name, 'r') do |f|
      if OPTS[:d]
        entry_text = hb_writer.delete_entry(f.read)
      elsif OPTS[:u]
-        hb_writer.update_entry(f.read, CATEGORIES)
+        e = hb_writer.update_entry(f.read, CATEGORIES)
+        puts e.uri
      elsif OPTS[:m]
        hb_writer.minor_update_entry(f.read, CATEGORIES)
      else
        entry_text = hb_writer.post_entry(f.read, CATEGORIES)
      end
    end
$ bundle exec hw -u blog/001.md
http://ongaeshi.hatenablog.com/entry/hatenablog-writer

バグ報告

動かないパターンを見つけたのでIssueに登録した。

contentに'<'が含まれるとエラー · Issue #1 · kymmt90/hatenablog-writer