ひがきの日記

2012-08-03

第55回 Ruby/Rails勉強会@関西でも ust してみた

前回同様、第55回 Ruby/Rails勉強会@関西にて無人 ust を敢行。

前日の夜に手順のおさらいをすると、LiveShell のファームウェアが自動更新された。
これでダッシュボードとの同期ができるようになったみたい!
やったね。

これで勝つる!!

ところが、今回はネットワーク回線の問題で失敗したみたい。

f:id:mas-higa:20120803213729p:image

Wi-Fi ルータには docomo の BF-01B を使ってる。*1
以前は e-mobile 使ってたけど、たまに電波の入らないことがあって買い替えた。

最初は調子良かったのが、だんだん回線品質が低下してきて、ついにはダッシュボードの同期もあやしくなってきた。

まだ半年ほど縛りはあるけど Xi とかに機種変更するか。


しかし冷静に考えてみると、docomo 3G の問題なのか、Wi-Fi の問題なのか、はっきりしない。

APが干渉なしで選べるチャネルのパターンでは、最大三つのAPしか置けないことが分かります([1、6、11]や、[2、7、12]、[3、8、13]、[4、9、14](日本のみ)のパターンしかありえない)。
無線LAN同士の干渉を考える ―― 無線にゃん

やはり Wi-Fi が問題なのかも?*2


そこでひらめいた!

BF-01B から有線でネットに接続できなかったっけ?
つまり、Internet ―― docomo ―(3G)― BF-01B ―(有線)― LiveShell という構成にすれば、どんなに Wi-Fi が干渉しても無問題 (ぉぃ

次回は BF-01B からの有線でチャレンジしたい。

*1:SP モードとか使わないから問題ない (よね?)

*2:この前、別の勉強会に参加した時も、参加者の数と Wi-Fi ルータの数が近似していた。

2012-05-26

第54回 Ruby/Rails 勉強会@関西で初級者向けレッスンやってきた

初級者向けレッスンを担当したので、以下スライドを解説。*1

スライドだけ欲しい人は直接どうぞ。

f:id:mas-higa:20120531220309p:image

Array とは

[1, 1, 2, 3]

[1, "two", [3, "3"], 4.0, :five]
  • まずは Array のリテラルを紹介。
  • 最初のは、Fixnum を 4つ持つ Array.
  • 次のは、Fixnum, String, Array, Float, Symbol の 5つの要素を持つ Array.

f:id:mas-higa:20120531220524p:image

Array とは (2)

a = [1, "two", [3, "3"], 4.0, :five]

a[0]      # => 1
a[-1]     # => :five
a[1] = "2nd"
a[3, 2]   # => [4.0, :five]
a[1..-2]  # => ["2nd", [3, "3"], 4.0]
a[5]      # => nil
  • 添字は 0 オリジン
  • 添字が負数なら後ろから数える
  • 代入できる
  • サイズを指定して取り出せる
  • 範囲を指定して取り出せる
  • 値がなければ nil

f:id:mas-higa:20120531220522p:image

Array オブジェクトの作り方

["a", "b", "c"] # => ["a", "b", "c"]
("a".."c").to_a # => ["a", "b", "c"]
[*"a".."c"]     # => ["a", "b", "c"]
%w[a b c]       # => ["a", "b", "c"]

f:id:mas-higa:20120531220520p:image

Array オブジェクトの作り方 (2)

"No Ruby, No Life.".scan(/\w+/)
  # => ["No", "Ruby", "No", "Life"]

"1,1,2,3,5,8".split(/,/)
  # => ["1", "1", "2", "3", "5", "8"]
  • String から Array を作ることがある。
  • 最初の例は、String#scan で単語を抽出。*4
  • 次の例は、String#split で、なんちゃって CSV

f:id:mas-higa:20120531220518p:image

Hash とは

{:AAPL=>566.71, :GOOG=>605.23}

{AAPL: 566.71, GOOG: 605.23}
    # => {:AAPL=>566.71, :GOOG=>605.23}
  • つづいて Hash のリテラルを紹介。
  • キーと値は => で区切る。
    • 1.9 からは下の表記を使える。(よりデータの羅列に見える)

f:id:mas-higa:20120531220510p:image

Hash とは (2)

h = {AAPL: 566.71, GOOG: 605.23}

h[:AAPL]      # => 566.71
h[:MSFT] = 31.16
h[:FB]        # => nil
  • Hash もアクセスには [ 角かっこ ] を使う
  • 代入できる (値の存在しないキーに対しても可)
  • 値がなければ nil

f:id:mas-higa:20120531221117p:image

Hash オブジェクトの作り方

a = [:AAPL, 566.71, :GOOG, 605.23]

Hash[*a]
    # => {:AAPL=>566.71, :GOOG=>605.23}
  • Array から Hash を作ることが (たまに) ある。
  • キーと値を羅列した Array を展開して Hash.[] で Hash オブジェクトを生成。
  • ファイルから読み込んだデータを String#split して Hash を生成するような用途。

順序がおかしくても気にしない

Hash[:AAPL, 566.71, :GOOG, 605.23]
  # => {:AAPL=>566.71, :GOOG=>605.23}
Hash[:AAPL, 566.71, 605.23, :GOOG]
  # => {:AAPL=>566.71, 605.23=>:GOOG}

素数奇数なら、

Hash[:AAPL, 566.71, :GOOG, 605.23, :FB]
# ~> odd number of arguments for Hash (ArgumentError)

あまり使わないけど、使うとハマる Array の初期化

f:id:mas-higa:20120531221115p:image

Array の初期化

Array.new(4, 0)     # => [0, 0, 0, 0]

a = Array.new(3, "ruby")
    # => ["ruby", "ruby", "ruby"]

a[0].upcase!        # => "RUBY"

a   # => ["RUBY", "RUBY", "RUBY"]
  • 値がないときも、nil 以外を返して欲しい
a = []

a[0] += 1
# ~> undefined method `+' for nil:NilClass (NoMethodError)

f:id:mas-higa:20120528214743g:image

全ての要素が同一のオブジェクトを指している。


では、どうするか?

そこでブロックですよ!

f:id:mas-higa:20120531221113p:image

Array の初期化 (2)

a = Array.new(3){"ruby"}
    # => ["ruby", "ruby", "ruby"]

a[0].upcase! # => "RUBY"

a   # => ["RUBY", "ruby", "ruby"]

ブロックで初期値を指定すると、別のオブジェクトになる。

f:id:mas-higa:20120528215806g:image

レッスンではサッと流したけど以下が重要。

次の例だと、せっかくブロック使っても無意味。

s = "ruby"
a = Array.new(3){s}
    # => ["ruby", "ruby", "ruby"]

a[0].upcase!  # => "RUBY"

a   # => ["RUBY", "RUBY", "RUBY"]

また、ブロックでは値が受け取れる。

a = Array.new(3){|i| i.to_s}
    # => ["0", "1", "2"]

Hash についても同じことがいえる。

f:id:mas-higa:20120531221112p:image

Hash のデフォルト

hash = Hash.new(0.0)  # => {}
hash[:AAPL]           # => 0.0

hash = Hash.new{|h, k| h[k] = ""}
                      # => {}
hash[:GOOG]           # => ""
hash[:IBM]            # => ""
※ キーの破壊
  • Hash はサイズを指定しない
    • サイズだけ指定されても、どのキーなんだよってことになる
  • ブロックには Hash と キーが渡される

キーの破壊

  • Hash はキーの hash メソッドで値の格納位置を決める (たぶん)
  • 格納位置の値が確かにそのキーの値であるか eql? メソッドで確認する (たぶん)

なので、キーを破壊すると、破壊前の格納位置に到達できなくなる (たぶん)

ただし、String をキーにしても、Hash のキーを破壊することはできない。

Ruby は String を特別に扱っている

  1. String オブジェクトをコピーして
  2. freeze する
key = "ruby"    # [あとでこわす]

h = {}
h[key] = "関西"
h   # => {"ruby"=>"関西"}

h.first                   # => ["ruby", "関西"]
h.first.first             # => "ruby"
h.first.first.eql? key    # => true   # 文字列は同じ
h.first.first.equal? key  # => false  # 別のオブジェクト
h.first.first.frozen?     # => true   # freeze されている

key.upcase!               # => "RUBY"
h   # => {"ruby"=>"関西"} # 破壊できない

f:id:mas-higa:20120531221110p:image

繰り返し each

[0, 1, 2].each{|i| puts i}

[0, 1, 2].each do |i|
  puts i
end

# >> 0
# >> 1
# >> 2
  • 繰り返しには each メソッドを使う
  • ブロックは { 波かっこ } または do end で囲む
    • ブロック内を繰り返す
    • 繰り返しのたびに i が順番に要素を指す

f:id:mas-higa:20120531221641p:image

繰り返し Enumerable

Array.ancestors
  # => [Array, Enumerable, Object, Kernel, BasicObject]
Hash.ancestors
  # => [Hash, Enumerable, Object, Kernel, BasicObject]
  • Enumerable
    • 繰り返しを行なうクラスのための Mix-in
    • クラスには each メソッドが必要

Enumerable という便利なモジュールがありまして、

f:id:mas-higa:20120531221638p:image

繰り返し Enumerable (2)

a = [2, 3, 5, 7]        # => [2, 3, 5, 7]

a.map{|i| i * i}        # => [4, 9, 25, 49]
a.select{|i| i.odd?}    # => [3, 5, 7]

a.inject{|s, i| s += i} # => 17

a.all?{|n| n.prime?}    # => true

それぞれのメソッドは「るりま」を見てね。きりがないし。*5

でも、この後、しょーもない紙芝居やるよりも inject の動きとか見た方が良かったんじゃないか、とスライド作りながら思ってた。*6

inject を教科書通りに呼ぶと、こんな感じ。

a = [2, 3, 5, 7]  # => [2, 3, 5, 7]

a.inject(0){|s, i| s += i}  # => 17

a.inject(0) do |s, i|
  puts "s = #{s} + #{i}"
  s += i
end

# >> s = 0 + 2
# >> s = 2 + 3
# >> s = 5 + 5
# >> s = 10 + 7

各ループで s と i は上記の値を指している。

つづいてスライドの例

a.inject{|s, i| s += i}     # => 17

a.inject do |s, i|
  puts "s = #{s} + #{i}"
  s += i
end

# >> s = 2 + 3
# >> s = 5 + 5
# >> s = 10 + 7

s の初期値が省略されると、s = a[0]; i = a[1] から繰り返しが始まる。

しかし、上級者になると、こんな書き方をする。

a.inject(&:+)               # => 17

f:id:mas-higa:20120531221635p:image

繰り返しと多重代入

a = [[:matz, 47], [:dhh, 32]]
a.size      # => 2

a.each{|i| puts "#{i[0]}(#{i[1]})"}

a.each{|name, age|puts "#{name}(#{age})"}

# >> matz(47)
# >> dhh(32)

ブロックの引数は、代入だと思ってみる。

i = [:matz, 47]
i       # => [:matz, 47]

name, age = [:matz, 47]
name    # => :matz
age     # => 47

さらに無理のある例、

f:id:mas-higa:20120531221632p:image

繰り返しと多重代入 (2)

a = [[1, [:matz, 47]], [2, [:dhh, 32]]]
a.size      # => 2

a.each do |id, (name, age)|
  puts "#{id}: #{name}(#{age})"
end

# >> 1: matz(47)
# >> 2: dhh(32)

これも代入だと

i = [1, [:matz, 47]]
i       # => [1, [:matz, 47]]

id, (name, age) = [1, [:matz, 47]]
id      # => 1
name    # => :matz
age     # => 47

かっこがないと、

id, name, age = [1, [:matz, 47]]
id      # => 1
name    # => [:matz, 47]
age     # => nil

f:id:mas-higa:20120531221629p:image

繰り返しと多重代入 (3)

h = {matz: 47, dhh: 32}

h.each{|i| puts "#{i[0]}(#{i[1]})"}

h.each{|name, age|puts "#{name}(#{age})"}

# >> matz(47)
# >> dhh(32)

Hash では、みんな自然と多重代入してた

h = {matz: 47, dhh: 32}

h.each do |i|
  puts i.class
  p i
end

# >> Array
# >> [:matz, 47]
# >> Array
# >> [:dhh, 32]

Hash#each すると、キーと値のペアが Array で渡される。


要素の数と引数の数が合わないと、どうなるのか?*7

# 引数が多い場合
i, j, k = [1, 2]
i   # => 1
j   # => 2
k   # => nil

# 引数が足りない場合
i, j = [1, 2, 3]
i   # => 1
j   # => 2

# 引数が足りなくても……
i, *j = [1, 2, 3]
i   # => 1
j   # => [2, 3]

ちょっと蘊蓄

f:id:mas-higa:20120531222112p:image

Array のコピー

a = [1, 2, 3]

b = a

a[0] = 0

a   # => [0, 2, 3]
b   # => [0, 2, 3]

f:id:mas-higa:20120528220146g:image

  • 代入はコピーじゃない
  • a が指す Array オブジェクトを b も指すようになった

f:id:mas-higa:20120531222111p:image

Array のコピー (2)

a = ["a", "b", "c"]

b = a.dup

a[0] = "A"

a   # => ["A", "b", "c"]
b   # => ["a", "b", "c"]
  • Object#dup*8 (または Object#clone) でコピー
  • 浅いコピーなので注意!

f:id:mas-higa:20120531222109p:image

Array のコピー (3)

a = ["a", "b", "c"]

b = a.dup

a[1].upcase!

a   # => ["a", "B", "c"]
b   # => ["a", "B", "c"]

f:id:mas-higa:20120528220708g:image

今回、話さなかったこと

[].respond_to? :each   # => true
  • ブロックは Proc
block = Proc.new{|i| i * 2}
[*0..4].map &block   # => [0, 2, 4, 6, 8]

block[5]             # => 10
a = [2, 3, 5, 7]
i = a.each
i.next  # => 2
i.next  # => 3
i.next  # => 5
i.next  # => 7
i.next  # ~> `next': iteration reached an end (StopIteration)

まとめ

  • Array と Hash の作り方・使い方
  • 繰り返しはブロックで
  • 浅いコピー・破壊に注意

演習問題は [あとでかく]

*1はてなダイアリーを使うと用語の説明が省略できるかな、と思って。

*2オブジェクトには型がある。

*3:離散範囲なら可能

*4:1.9 でマルチバイト文字列から単語を抽出するには /\p{Word}+/ を使う

*5:Integer#prime? は require 'prime' しないと使えない

*6:紙芝居を作ってるうちに楽しくなってきて、こんなスライドに……

*7:質問されたけど、答えを用意してなかった

*8:duplicate の略 (だよね?) なので <でゅぷ> って読んでたけど <だっぷ> と読む説がある