Effective Ruby: superってメソッドとちゃうんやで

項目7 superのふるまいがひと通りでないことに注意しよう

Effective Ruby

Effective Ruby

super

superってメソッドではなくキーワードだったんですね。
supersuper()で挙動が異なるなんて知りませんでした!
(もしかすると昔学んだかもしれないが、忘れている。)
 

class SuperSilliness < SillyBase
  def m1(x, y)
    super(1, 2) # 1と2を渡して呼び出し
    super(x, y) # xとyを渡して呼び出し
    super x, y  # 上と同じ
    super       # 上と同じ
    super()     # 引数なしで呼び出し
  end
end

最後2つ要注意。

override

(例が微妙だけど)この場合、includeがoverrideされてしまう。
なので継承ではなく合成(composition)を使うこと検討した方が良いと指摘されている。

module CoolFeatures
  def feature_a
  end
end

class Vanilla
  include(CoolFeatures)

  def feature_a
    super # CoolFeatures#feature_a
  end
end

method_missing

通常、定義されていないsuperを呼び出すとこうなる。

class SuperHappy
  def laught
    super
  end
end

>> SuperHappy.new.laught
NoMethodError (super: no superclass method `laught' for #<SuperHappy:0x00007f84608744e8>)

method_missingを定義していると気付かない。

class SuperHappy
  def laught
    super
  end

  def method_missing(args)
    p args
  end
end

>> SuperHappy.new.laught
:laught

Amazon Echo Dot(Alexa)を活用してみる

買ってから2ヶ月くらいほったらかしにしていたAmazon Echo Dot(Alexa)をちゃんと使ってみました。Echo Dotはサイズ感も手頃で良いです。 反応がとても良く、そこそこ便利です。あとIFTTTやっぱ便利だわ。
今後は照明をHue or IKEA のやつにしようか思案中。
 

Amazon Echo Dot (Newモデル)、ブラック

Amazon Echo Dot (Newモデル)、ブラック

Wunderlist連携

ちょっとしたTodo管理にはWunderlistを使っていて、これを音声で登録できると捗るわと思っていました。
Wunderlistは、iPhone&PC両方使いやすので気に入っています。(MSに買収されてこの先どうなるかわかりませんが)

やり方

Wunderlist のAPI叩いたりするのかと思えば、「Alexa -> IFTTT -> Gmail」という方法でできたのでした。IFTTT便利。
参考:Amazon Echo Dotの壁掛け設置から便利な活用法までを紹介 - karaage. [からあげ]
 
「Alexa やることリストに○○を追加して」でできるようになりました。
(注意点としては、Alexa側のやることリストは溜まりっ放しになる。まぁ無視できるかな。)

家電連携(IRKit)

Siri - Raspberry Pi - iRKit でエアコン操作 - rochefort's blog
現状、「iPhone(Siri) -> Raspberry Pi(Homebridge) -> iRKit」でテレビとエアコンのON/OFFを実施していたのですが、Siriの反応が鈍いのでAlexaに乗り換えて見ました。
 

やり方

「Alexa -> IFTTT(WebHook) -> iRKit APIへPOST -> iRKit」という流れになり、Raspberry Pi が不要になってしまいました。
また、iRKit買った当初からセキュリティの問題もあり危惧して未使用だったのですが、インターネット経由で家電操作することになります。家電のスイッチを入れるためだけに。hackしないでね。
 
参考:Amazon Echo(Alexa)とIRKitをIFTTTで連携してホームオートメーション - Usual Software Engineer
   
 
とりあえず「Alexa テレビ トリガー」でできるようになりました。
いやぁ、これは微妙だ。
 

Node-RED

調べてみると Node-RED を使うとスマートホームスキルを利用することができるようです。
 
参考:Amazon Echoとラズパイで、音声で照明をon/offする - Qiita
これは良さそう。あとでやろう。
 

タイマー

キッチンタイマーとして、いつもSiriを使っていたのですが、これもAlexaに乗り換えです。
「Alexa ○分測って」で開始。
止め方が分からなかったのですが、「Alexa タイマー消して」でok。
 
 

JR遅延情報

参考:Amazon Echoがあれば列車の遅延情報もお知らせしてくれます | ギズモード・ジャパン
「Alexa JR東日本の情報を教えて」みたいな感じ「Alexa JR東日本を開いて」でいけます。
終了するときは、「終了」。

天気

「Alexa 天気教えて」でOK。

たまに音楽

Spotifyがメインなので、たまにAmazon Music

Effective Ruby: 特異クラスとかその辺の話

項目6 Rubyが継承階層をどのように組み立てるかを頭に入れよう

「項目5 実行時の警告に注意しよう」-wオプションと$VERBOSE変数の話でした。
知っているべき内容ですが、既に理解している内容だったので1個飛ばし。

 
内容的には、include時に不可視な特異クラスがスーパークラスとしてクラス階層に挿入されること、 特異メソッドの説明、クラスメソッドが特異クラスのインスタンスメソッドとして格納されること、 メソッドの探索のプロセスについて書かれています。
 
もちろん、正しいことが書かれていますが、少々わかりにくい。
ここは、メタプログラミングRubyの方が分かりやすいかと思いました。

メタプログラミングRuby 第2版

メタプログラミングRuby 第2版

ついで

なんとなく分かりにくいので、自分の整理用のためにも、本書の補足としてsample codeと関連および派生したコードと図を一緒に描いて見ました。
この1個右に入っって上をたどるというメソッド探索の流れは図にしないと分かりにくい。
(※図のKernelは省略)
 

1. インスタンスメソッド

まずは、本書よりも簡単な例。
単なる継承の場合。

class Person
  def name
  end
end

class Customer < Person
end

customer = Customer.new
customer.respond_to?(:name)
=> true

# 両方ともインスタンスメソッドが存在する
Customer.instance_methods(:false)
Person.instance_methods(:false)

f:id:rochefort:20180208175509p:plain
これは良いですよね。

特異メソッド

続いて特異メソッド。

class Person
  def name
  end
end

class Customer < Person
end

# addressメソッドを追加
customer = Customer.new
def customer.address
end


# ここにはいない
Customer.instance_methods(:false)
Person.instance_methods(:false)

# 特異クラスの確認
>> customer.singleton_class
=> #<Class:#<Customer:0x00007f8848838650>>

# ここにいる
customer.singleton_class.instance_methods(:false)

# 特異クラスの親クラスはCustomer
>> customer.singleton_class.superclass
=> Customer

f:id:rochefort:20180208175524p:plain

3. include(本書の例)

module ThingsWithNames
  def name
  end
end

class Person
  include ThingsWithNames
end

class Customer < Person
end

>> customer = Customer.new
>> customer.respond_to?(:name)
=> true


# ここにはいない
Customer.instance_methods(:false)
Person.instance_methods(:false)


# 継承関係を確認。  
>> Customer.ancestors
=> [Customer, Person, ThingsWithNames, Object, Kernel, BasicObject]

>> Customer.included_modules
=> [ThingsWithNames, Kernel]

# ThingsWithNamesが差し込まれており、ここにいる
>> ThingsWithNames.instance_methods(false)
=> [:name]

f:id:rochefort:20180208175542p:plain

4.extendした場合は?

extendした場合も見て見ましょう。

module ThingsWithNames
  def name
  end
end

class Person
  extend ThingsWithNames
end

class Customer < Person
end

>> Customer.respond_to?(:name)
=> true


# ここにはいない
Customer.methods(false)
Person.methods(false)


# 継承関係
>> Customer.ancestors
=> [Customer, Person, Object, Kernel, BasicObject]

>> Customer.included_modules
=> [Kernel]


# ThingsWithNames が消えました。  
# どこにいるかというと、特異クラスの継承ツリーに存在します。  
>> Customer.singleton_class.ancestors
=> [#<Class:Customer>, #<Class:Person>, ThingsWithNames, #<Class:Object>, #<Class:BasicObject>, Class, Module, Object, Kernel, BasicObject]

>> ThingsWithNames.instance_methods(false)
=> [:name]

f:id:rochefort:20180208175557p:plain

Effective Ruby

Effective Ruby