0

Rubyのhoistingみたいなの

めんどうくさくてRuby1.8.7から上げていないままのアプリがあって、ちょっと修正したら動かなくなった。

JavaScriptにホイスティングというのがあって〜〜という話を〓が前に言っていて、へぇ〜と思っていたらRubyでも似たのが発生していた

hoisting.rb

urls = ["http://shokai.org/blog", "https://shokai.github.com", "http://example.com"]
url = "hoge"

puts url

urls.delete_if{|url| url =~ /shokai/ }
p urls

puts url


各Rubyで実行した結果


1.8.7だけ、変数urlの中身が書き換わっている。


どうしょうもないので、何かイテレータにしか使わなそうな名前を使うとか、_urlみたいな変数名を使うとかしないとならない。
urls.delete_if{|i| i =~ /shokai/ }

4年ぐらいRuby使ってるけど始めて遭遇したと思う

0

RubyのlambdaやProcとblock渡しとコールバック関数

先日のRuby初級入門2013で事前に「Rubyのlambdaとかblockとか教えて」と言われていたけど、どうみても初心者向けの内容ではないので無視していたので解説する


lambda{ コード }とProc.new{ コード }の差がよくわからない

ここ読め
RubyでlambdaとProcの違いは? – QA@IT
rubyのlambdaとprocの比較実験 – Qiita [キータ]
まとめると
内部でreturnした時と、引数の数が違うときの挙動が違うそうです


block渡しを使ったイベント登録について

do 〜 endブロックで渡された処理はすぐにyieldで返さなくてもいい


block渡しを受け取れる関数を宣言する方法

例えば、フィボナッチ数列を次々と生成する場合を考える。
フィボナッチ数列は無限に続くので、計算が終わらない。
無限に終わらない処理は結果をreturnで返せないので、1つフィボナッチ数を生成するごとにコールバック呼び出しで結果を通知する仕様にする。

Fib#start(&block) 関数を宣言すると、その中の block_given? でブロック渡しされたか判定できる
# -*- coding: utf-8 -*-
## フィボナッチ数列を1つずつ計算し、1つずつコールバックで返す

class Fib
def initialize
@f0 = 0
@f1 = 1
end

def start(&block)
loop do
f2 = @f0 + @f1 # フィボナッチ数列を計算
@f0 = @f1
@f1 = f2
if block_given? # ブロック渡しされているかどうかチェック
yield f2 # コールバック呼び出し
else
puts f2 # コールバック関数が登録されてない場合、自前で標準出力する
end
break if f2 > 1000000 # キリがないので終了
end
end
end

## フィボナッチ数計算開始 ##

## コールバックなしで計算スタート
Fib.new.start


## コールバック関数登録しつつ、計算スタート
Fib.new.start do |num|
puts "フィボナッチ数列 #{num}"
sleep 1
end
このように、時間がかかるor無限に計算が終わらない処理はコールバックで結果を返すといいと思います。
Webクローラとか。
〜〜のページを取得中、完了、などを計算する側でprint出力しているとコードが汚くなります。経過をお知らせするのもコールバック関数を登録する方式でやればいい。


コールバック関数を何個でも登録できるようにする

Fib#start 関数を実行する前に、コールバック関数を登録しておく。
長い処理の場合、計算の経過を通知・計算結果を表示・ファイルに保存・twitterに通知・・・等と色々やりたい場合がある。
コールバックを1つしか登録できないよりも、複数のコールバックを登録できるようにした方がいい。

コールバック登録関数 Fib#regist_callback(&block) を作り、&blockを普通に配列に貯めて、あとで使う。
# -*- coding: utf-8 -*-
## 複数のコールバックを登録する例

class Fib
def initialize
@f0 = 0
@f1 = 1
@callbacks = Array.new # コールバック関数を保存しておく配列
end

def regist_callback(&block) # コールバック関数を登録する
raise ArgumentError, "block not given" unless block_given? # 正しくblockが渡されない場合、エラーを投げる
@callbacks.push block
end

def start
loop do
f2 = @f0 + @f1 # フィボナッチ数列を計算
@f0 = @f1
@f1 = f2
@callbacks.each do |c| ## 全てのコールバック関数を順に呼び出す
c.call f2
end
break if f2 > 1000000 # キリがないので終了
end
end
end

## フィボナッチ数計算開始 ##
fib = Fib.new

# 1つ目のコールバック関数を登録する
fib.regist_callback do |num|
puts "フィボナッチ数列 #{num}"
end

# 2つ目のコールバック関数を登録する
fib.regist_callback do |num|
puts "result = #{num}"
end

fib.start ## 計算開始


&blockとは何か

do 〜 endが&blockに渡る。
&blockをprintしてみれば何なのかわかる。
# -*- coding: utf-8 -*-

def func(arg0, arg1, &block)
if block_given?
puts "blockとは -> #{block}"
block.call "ほげ", "ふが"
else
puts "block not given"
end
end

func 1, 2 do |a, b|
puts "this is block (#{a}, #{b})"
end

proc = Proc.new{|a, b|
puts "this is block 2 (#{a}, #{b})"
}
func(1, 2, &proc)

結果
blockとは -> #<Proc:0x007ff85410ca08@block.rb:12>
this is block (ほげ, ふが)
blockとは -> #<Proc:0x007ff85410c850@block.rb:16>
this is block 2 (ほげ, ふが)
&blockはProcだった。
doで渡しても、Proc.newを参照渡ししても同じように動く。


EventEmitterでコールバックを管理する場合

コールバック関数を登録するための関数を自分で用意する必要がなくなる、EventEmitterというrubygemを作りました。

インストール

gem install event_emitter

使ってみる

クラスにincludeするとイベント管理機能が追加されます。だいぶ綺麗に書けるようになりましたね
# -*- coding: utf-8 -*-
## 複数のコールバックをEventEmitterで管理する例

require 'rubygems'
require 'event_emitter'

class Fib
include EventEmitter # EventEmitterを使う

def initialize
@f0 = 0
@f1 = 1
end

def start
loop do
f2 = @f0 + @f1 # フィボナッチ数列を計算
@f0 = @f1
@f1 = f2
emit :number, f2 # numberイベントを発行
break if f2 > 1000000 # 終了
end
emit :end # 終了イベントを発行
end
end

fib = Fib.new

# 1つ目のコールバック関数を登録する
fib.on :number do |num|
puts "フィボナッチ数列 #{num}"
end

# 2つ目のコールバック関数を登録する
fib.on :number do |num|
puts "result = #{num}"
end

# 終了イベントを登録する
fib.on :end do
puts "終了しました"
end

fib.start ## 計算開始
コールバック関数を分類できるようになってる。
この例では:numberと:endという2種類のコールバックを登録している。それぞれ、新しいフィボナッチ数が作られた時と、計算が終わった時に呼び出される。
event_emitterにはコールバック解除のremove_listener関数や、1回呼び出されたら消滅するコールバック once なども付いてきて大変便利。


最近作ったもので、わかりやすい例

を紹介すると
twitterでエゴサーチしてSkypeに通知するやつや、gyazzの差分を監視してSkypeに通知するやつは両方共event_emitterを活用していてエラーもクロールの経過報告も取得したページも全部コールバックを登録して受け取るようになっています。

0

設定ファイルの読み込みにHashie::Mash使ってる

最近こうやってる


inits/config.rb

require 'yaml'
require 'hashie'

module MyApp
Config = Hashie::Mash.new YAML.load File.open(File.expand_path "../config.yml", File.dirname(__FILE__)).read
end

1つ上の階層のconfig.ymlを読んでHashie::Mashにしてから、モジュール直下の定数に入れておく

こんな階層の深い設定ファイルの場合でも、
MyApp::Config.twitter.user で “shokai”が取得できたり、
MyApp::Config.ignore.wordsで無視する単語リストが配列で取得できたりする。

twitter:
user: "shokai"

skype:
chat: "#shokaishokai/$564697b405245f4f"

words:
- "shokai.org"
- "橋本商会"
- "github.com/shokai"
- "shokai.github"

ignore:
users:
- bot
- shokai_twit
- shokai_bot
- shokai_log
- end_0606_shokai
- kirakira
- rurourafale
- YADAYOOOOOO
- aine0120
- K_T_Hotel_Annex
- sho1nco
- koyoshokai
words:
- shokai_bot
- shopping.yahoo
- キラキラ商会
- kirakira
- ビリケン商会

0

Ruby初級入門という勉強会やりました

まず全員Ruby2.0.0をインストールさせつつ、俺がRubyの色々なことを紹介したり、ライブコーディングした。

今日の資料です

Rubyそこそこ使ったことある人と全く使ったこと無い人が半々だった。
使ったことある人は前半がためになったとのこと。
ない人は後半のArrayやHashにsortやuniqやreverseなどをチェーンしていったり、mixやmaxやfindなど痒い所に手がとどくの良かったようだ。


スライドを前日からtwitterで公開していたら、@shigeyas先生からgem紹介にpryとawesome_printがあったほうがいいのでは、というツッコミがあって追加した。

「gemの使い方を調べる」のところでpryとawesome_printを使って色々調べるのも追加した。

教育体験のせいで1時間以上のスライドでも3時間ぐらいあれば作れるようになってしまった。


実演

最後にぶっこ抜き実演をやった。ぶっこぬきはクロール・HTML解析・DBに貯めて・通知するという総合芸術で、しかも日常的に使うから不満もすぐたまって改良欲求が高くなる。
自分で愛用できるツールを作って運用メンテしていくことがプログラミング学習の早道だと思うので、ぶっこ抜きをテーマにした。


教えていた人の中にデータマイニングが好きな奴がいたので、アニメスタッフデータベースというすごいwikiから制作スタッフが名をたくさん取ってくるクローラを書いた。お腹がすいたので完成せず終了して麺の月に行った。

役職名と名前が取得できるところまでは作った。あとは協調フィルタリングとかで便利なレコメンドwebサービス作れると思う。

ソース

0

他人のGitHubのissue一覧を見れるようにした

ソース
https://github.com/shokai/github-cmd


これの続き
橋本商会 » githubの自分のリポジトリのissue一覧を見るツール
橋本商会 » githubのissue見るコマンドにissue番号だした

他人やorganizationのリポジトリのissue一覧を見れるようにした。
ちょっかいかけたい人や就職したい組織に対して、issueにpull requestして存在感をアピールするのに有効だと思う。

実行時引数に複数の名前を入れられるので

% github-issues shokai masuilab masui --all
で自分と研究室と先生のissueが全部まとめて日付順で見れる。