プリティーウーマンにツイーヨを読み上げてもらう

やままです。

プリティーウーマンがツイーヨを読み上げてくれるプログラムを(2ヶ月前に)つくりました!これで寂しい夜も平気です!!!

https://github.com/remain/kyoko

概要

  • 任意の単語で twitter をリアルタイム検索する
  • それを OS Xsay コマンドをつかって読み上げてもらう
    • デフォルトだと英語しかしゃべれない
    • Kyoko さんっていう日本語がしゃべれるスーパーキュートなウーマンがいるからどうにかしてインストールする(インストール方法わすれた)

きっかけ

いつだかライブコーディングで作ったんだけど、ぼろぼろすぎてくやしかったから作りなおした。

使いみち

わからん。たぶんない。

Ruby の Prime がつよい

いろいろあって Prime クラスのソースを読んでいたらとても勉強になったよ。

Prime

  • 素数全体を表すクラスだよ
  • 素数全体というオブジェクトは1つしか存在しえないので、シングルトンになるよ
  • 利便性のため、デフォルトインスタンスのメソッドをクラスメソッドとしても使用できるよ
  • Prime.new で Ruby 1.8 の Prime の互換クラスのインスタンスを生成できるよ

ソースをよむ

lib/prime.rb から必要部分を抜粋するよ。

require "singleton"
require "forwardable"

class Prime
  include Enumerable
  @the_instance = Prime.new
 
  # obsolete. Use +Prime+::+instance+ or class methods of +Prime+.
  def initialize
    @generator = EratosthenesGenerator.new
    extend OldCompatibility
    warn "Prime::new is obsolete. use Prime::instance or class methods of Prime."
  end
 
  class << self
    extend Forwardable
    include Enumerable
    # Returns the default instance of Prime.
    def instance; @the_instance end
 
    def method_added(method) # :nodoc:
      (class<< self;self;end).def_delegator :instance, method
    end
  end
  
  module OldCompatibility
  end
end

シングルトンパターン

さらに抜粋していくよ。

class Prime
  @the_instance = Prime.new
  
  class << self
    # Returns the default instance of Prime.
    def instance; @the_instance end
  end
end

Singleton モジュールは使わずにシングルトンパターンを実現しているよ。どうしてだろう。

旧 Prime 互換クラスのインスタンス

class Prime
  @the_instance = Prime.new

  # obsolete. Use +Prime+::+instance+ or class methods of +Prime+.
  def initialize
    @generator = EratosthenesGenerator.new
    extend OldCompatibility
    warn "Prime::new is obsolete. use Prime::instance or class methods of Prime."
  end
  
  module OldCompatibility
  end
end

OldCompatibility モジュールには旧 Prime 互換のインスタンスメソッドが宣言されているよ(中略しているよ)。 これを extend することによって、Prime.new で生成したインスタンスに特異メソッドを定義しているんだね。 互換が不要になったら OldCompatibility モジュールを削除するだけで済むからつよいよ。

Singleton モジュールを include すると Prime.new がプライベートクラスメソッドになってしまうから、旧 Prime 互換クラスのインスタンスを生成するためには Singleton モジュール を使わずにシングルトンパターンを実現する必要があったんだね。

ちなみに、デフォルトインスタンスを生成した時点では Prime.initialize は定義されていないから、このとき生成したインスタンスには OldCompatibility モジュールは extend されないよ。すごいね。

デフォルトインスタンスのメソッドをクラスメソッドとして使用する

class Prime
  class << self
    extend Forwardable
    
    def method_added(method) # :nodoc:
      (class<< self;self;end).def_delegator :instance, method
    end
  end
end

Fowardable モジュールを extend しているね。 Fowardable モジュールはクラスに対してメソッドの委譲機能を定義するモジュール。 この場合は、method_added の引数 method を instance に委譲するよ。

(class<<self;self;end) の戻り値は Prime の特異クラス。 ここでの self は Prime だから、Prime のクラスメソッドを定義するためには (class<<self;self;end) をレシーバにする必要があるんだね(class << self の中にまた class << self が出てくるからわかりづらいよね)。

Module#method_added はクラスやモジュールにインスタンスメソッドが定義されたときに呼び出されるメソッドだよ。 Prime にインスタンスメソッドが追加されると method_added が呼ばれて同名のクラスメソッドを定義、処理をデフォルトインスタンスに委譲することによって、デフォルトインスタンスのメソッドをクラスメソッドとして使用することができるんだね。

まとめ

よくわからない文体で書くのやめよう。

Ruby で文字列の表示幅をもとめるおはなし

Ruby には文字列の表示幅を求めるメソッドがありません(ニッチ)。 要は ASCII 文字を1文字、非 ASCII 文字(= マルチバイト文字)を2文字としてカウントしたいんです(ニッチ)(ニッチ)。

こんな感じで求めてみる

"hogeふが".chars
=> ["h", "o", "g", "e", "", ""]
# String#chars で1文字ずつにばらす

["h", "o", "g", "e", "", ""].map { |c| c.ascii_only? ? 1 : 2 }
=> [1, 1, 1, 1, 2, 2]
# ASCII 文字を1文字、非 ASCII 文字を2文字としてカウント

[1, 1, 1, 1, 2, 2].inject(0, &:+)
=> 8
# みんなだいすき Enumerable#inject で合計を求める

できた

class String
  def width
    self.chars.map{ |c| c.ascii_only? ? 1 : 2 }.inject(0, &:+)
  end
end

"hogeふが".width
=> 8

だがしかし

ちょっと効率がわるい(each が2回まわる)

作戦変更

"hogeふが".chars.reject(&:ascii_only?)
=> ["", ""]
# Array#reject で ASCII 文字を取り除く(= 非 ASCII 文字を抽出)

"hogeふが".length + ["", ""].length
=> 8

できた(2回目)

class String
  def width
    self.length + self.chars.reject(&:ascii_only?).length
  end
end

"hogeふが".width
=> 8

まとめ

Enumerable#inject だいすき

CentOS 6.4 で Windows の共有フォルダをマウントしたおはなし

Windows

共有フォルダ作成

  1. 共有フォルダをつくります
  2. アクセス許可で "変更" を許可します

ファイアウォールの設定変更

Windowsファイアウォールはデフォルトだと違うセグメントからのアクセスはぜんぶ破棄するようです。違うセグメントから共有フォルダにアクセスする場合は TCP 445 をあける必要があります。これのせいでめっちゃはまった。

CentOS

Samba のインストール

$ sudo yum install samba-client cifs-utils

エントリポイント作成

$ mkdir ~/share

マウント

$ sudo mount -t cifs -o user=[win_user]%[win_password] /[win_ip_addr]//[win_shared_directory] ~/share

// アンマウント
$ sudo umount -l ~/share

fstab の設定

起動時に自動でマウントするように fstab を設定します

$ sudo vi /etc/fstab
+\\[win_ip_addr]\[win_shared_directory] /home/[linux_user]/share cifs uid=500,gid=500,file_mode=0644,username=[win_user],password=[win_password] 0 0

fstab の反映
$ sudo mount -a

Centos 6.3 に GitLab 6.0 をいれたおはなし

GitHub クローンの GitLab を導入してみました。

MySQL の GitLab ユーザ作成

# mysql -uroot -p
mysql> grant all on gitlabhq_production.* to gitlab@localhost identified by '[PASSWORD]';
mysql> exit

Redis のインストール

# yum install redis --enablerepo=epel
# chkconfig redis on
# service redis start

依存パッケージのインストール

# yum install libicu-devel

GitLab ユーザ作成

# useradd git

GitLab ユーザの git 設定

# su - git

$ git config --global user.name  "GitLab"
$ git config --global user.email "gitlab@git.example.jp"

GitLab shell のインストール

$ git clone https://github.com/gitlabhq/gitlab-shell.git
$ cd gitlab-shell
$ git checkout v1.7.0
$ git checkout -b v1.7.0

$ cp config.yml.example config.yml
$ vi config.yml
gitlab_url: http://[FQDN]

$ ./bin/install

GitLab インストール

$ cd
$ git clone https://github.com/gitlabhq/gitlabhq.git gitlab
$ cd gitlab
$ git checkout v6.0.0
$ git checkout -b v6.0.0

$ cp config/gitlab.yml.example config/gitlab.yml
$ vi config/gitlab.yml
production:
  gitlab:
    host: [FQDN]
    email_from: gitlab@[FQDN]
    support_email: support@[FQDN]

$ cp config/database.yml.mysql config/database.yml
$ vi config/database.yml
production:
  username: gitlab
  password: ""

$ mkdir tmp/pids/

$ bundle install --deployment --without development test postgres
$ bundle exec rake db:create RAILS_ENV=production
$ bundle exec rake gitlab:setup RAILS_ENV=production

あとは Passenger とかで適に。 GitLab さんアイコンがキモいのだけゆるせない。

CentOS 6.4 で git のバージョンをあげたおはなし

CentOS 6 標準の git はちょっと尋常じゃなくバージョンがひくい(#^ω^)

もとのバージョン

$ git --version
git version 1.7.1

ひくい

忌まわしき CentOS 6 標準の git をけす

$ sudo yum remove git

RPMForgeリポジトリ追加

$ sudo rpm --import http://apt.sw.be/RPM-GPG-KEY.dag.txt
$ sudo rpm -ivh http://pkgs.repoforge.org/rpmforge-release/rpmforge-release-0.5.3-1.el6.rf.x86_64.rpm
$ sudo vi /etc/yum.repos.d/rpmforge.repo
-enabled = 1
+enabled = 0

インストール

$ sudo yum --enablerepo=rpmforge-extras install git

あがった

$ git --version
git version 1.7.11.3

追記

epel に 1.8.2 があることに気がつきました(最近あらわれた?)。最初からこっちでいいじゃん。

CentOS 6.4 に vim 7.3 をいれたおはなし

yum のやつはちょっと古い(#^ω^)

とりあえず yum のやつを消す

$ sudo yum remove "vim*"
(略)
Dependency Removed:
  sudo.x86_64 0:1.8.6p3-7.el6

ファッ!?

$ where sudo
sudo not found

sudo の霊圧が消えた

落ち着いて sudo をいれなおす

$ su - 
# yum install sudo
(略)
Dependency Installed:
  vim-minimal.x86_64 2:7.2.411-1.8.el6

vim-minimal さん…

# mv /etc/sudoers.rpmsave /etc/sudoers
# exit

vim-minimal さんは気にしないことにして乱暴に sudo の設定をもどした

気を取り直して vim 7.3 のソースをもってくる

公式Linux のひとは mercurial つかうよね?ね?便利だよね?(意訳)とかいってるから mercurial でもってくる

$ sudo yum install mercurial

$ cd /usr/local/src
$ sudo hg clone https://vim.googlecode.com/hg/ vim73

ドヤ顔で mercurial でもってくる(キリッ とかいったけどはじめて mercurial つかった

公式を眺めていてあることに気づいた

2週間くらいまえに 7.4 がでている
なんかよくわからないから 7.3 にしたい。よくわからないなりに hg log とかうったらコミットログ?がでてきたので 7.3 の最終コミットのハッシュをもってくる。よくわからないなりに hg co 29e57603bf6f とかうったら 7.3 になった(たぶん)。

ようやくインストール

$ cd vim73
$ sudo ./configure --with-features=huge --enable-multibyte --enable-rubyinterp --enable-luainterp --disable-selinux 
$ sudo make
$ sudo make install

できたよー

$ where vim
/usr/local/bin/vim
$ vim --version
VIM - Vi IMproved 7.3 (2010 Aug 15, compiled Aug 29 2013 00:02:01)

追記

vim-minimal さんは実質 vi でした。たぶん visudo とかあるから sudo の依存パッケージになってるんじゃないかな~