RubyのComparableモジュールで比較を実装
- 作者: Peter J.Jones
- 出版社/メーカー: 翔泳社
- 発売日: 2015/01/19
- メディア: Kindle版
- この商品を含むブログ (5件) を見る
項目13 "<=>"とComparableモジュールで比較を実装しよう
例にでてくるのはバージョンの比較を実装する時の話。
例えば、"10.10.3"と"10.9.8"のような比較の場合どうするか?
Object#<=>
2つのオブジェクトが等しいかどうかをテストするだけの汎用メソッド。
class Version attr_reader(:major, :minor, :patch) def initialize(version) @major, @minor, @patch = version.split(".").map(&:to_i) end end >> %w(10.10.3 10.9.8).map { |v| Version.new(v) }.sort ArgumentError (comparison of Version with Version failed) # オブジェクトが等しくなければnilを返す >> v1 = Version.new("10.10.3") >> v2 = Version.new("10.9.8") >> v1 <=> v2 => nil
なので<=>を実装する
class Version attr_reader(:major, :minor, :patch) def initialize(version) @major, @minor, @patch = version.split(".").map(&:to_i) end # 追加 def <=>(other) return nil unless other.is_a?(Version) # 各桁を比較し0でないものがあればその値を返す。全部0なら0を返す。 [ major <=> other.major, minor <=> other.minor, patch <=> other.patch, ].detect { |n| !n.zero? } || 0 end end >> Version.new("10.10.3") <=> "a" => nil >> Version.new("10.10.3") <=> Version.new("10.11.3") => -1 >> Version.new("10.11.3") <=> Version.new("10.10.3") => 1 >> Version.new("10.10.3") <=> Version.new("10.10.3") => 0
ついでに比較演算子
"<", "<=", "==", ">", ">=" はComparableモジュールをincludeすればok。
class Version include Comparable # これ追加 attr_reader(:major, :minor, :patch) def initialize(version) @major, @minor, @patch = version.split(".").map(&:to_i) end def <=>(other) return nil unless other.is_a?(Version) [ major <=> other.major, minor <=> other.minor, patch <=> other.patch, ].detect { |n| !n.zero? } || 0 end end >> v1 = Version.new("10.10.3") >> v2 = Version.new("10.11.3") >> [v1 < v2, v1 <= v2, v1 == v2, v1 >= v2, v1 > v2] => [true, true, false, false, false] >> Version.new("10.10.10").between?(v1, v2) >= true
覚えておくべき事項
- オブジェクトの順序は、"<=>演算子を定義し、Comparableモジュールをインクルードして実装しよう
- "<=>"演算子は、左日演算子が右日演算子と比較できないものならnilを返す。
- クラスのために"<=>"を実装した場合、特にインスタンスをハッシュキーとして使うつもりなら、eql?を"=="の別名にすることを検討しよう。 別名にする場合には、hashメソッドもオーバーライドしなければならない。
最後のやつは、こんな感じに実装すると良い。
class Version alias_method(:eql?, :==) def hash [major, minor, patch].hash end end
facebookのosqueryがキモすごい
プロセスとかハードウェアの情報をSQL likeに取得できるすごいツール。
詳しく読んでないですが、CLIだけでなくdaemonとして動かして結果も記録できるとのこと。
osquery | Easily ask questions about your Linux, Windows, and macOS infrastructure
物によってはコマンド打つより、見やすくていいかもしれない。
こんな感じ
SELECT DISTINCT process.name, listening.port, process.pid FROM processes AS process JOIN listening_ports AS listening ON process.pid = listening.pid WHERE listening.address = '0.0.0.0';
他には
以下にテーブルがまとまってます。現時点で194テーブル。
osquery | Schema
(いつからかMacで見れなくなっていたbluetoothデバイスの電池残とか見れないかなぁと探して見たのですが、見つかりませんでした。)
Amazon Echo Dot(Alexa)とNode-REDで家電をスマートホームに対応させる
最近、Echo(Alexa)をそこそこ使っています。
特にエアコンのオン・オフは便利でおすすめです。
Amazon Echo Dot(Alexa)を活用してみる
IFTTT + トリガーの問題点
便利は便利なのですが、 現状は は、IFTTT + トリガーで実行しているため、最後に「トリガー」と言わなければいけませんでした。
具体的には、「Alexa エアコンオン トリガー」みたいな感じでした。
すごい不自然です。
Node-RED でスマートホームに対応させる
スマートホームに対応させることで「Alexa エアコンつけて」という感じでとても自然な言い回しになります。
通常スマートホームは、家電側が対応していないと利用できないのですが、Node-RED Alexa Home Skill Bridge を利用することで、スマートホームに登録することができます。Alexaの呼び出しをNode-RED側で受けてコマンド実行(今回はcurlでpost)することでiRkitから赤外線を送信し家電を操作することができます。
概要図
ざっくりこんな感じ。
Node-REDの実行環境はRaspberry Piを利用しています。
参考
- Echosim.ioを使うと日本でもAlexaでSmart Homeを実現できるので、安価なBlack Beanで照明やエアコンを制御してみた - 知的好奇心 for IoT
- 【IoT】4.Node-REDの設定をしてみる - そこらへんのパパの独り言
やり方ざっくり
細かいやり方は、上記リンクに記載されているので割愛します。
- Node-RED Alexa Home Skill Bridgeのエンドポイントにユーザ・デバイス情報の登録
- AlexaアプリでスマートホームスキルにNode-REDを追加、アカウントのリンク、デバイスを追加
- Node-RED を実行環境(Raspberry Pi)にインストールしデーモンとして実行、Node-REDのフローを作成
Node-RED Alexa Home Skill Bridge
肝は Node-RED Alexa Home Skill Bridge で、ここにデバイスを登録することで、Alexaアプリのスマートホームにデバイスを追加することができ、後述のNode-REDでフローを定義することができます。
なのでユーザ登録およびデバイスの登録が必要です。
デバイス登録例:
デバイス情報の使われ方
Node-RED
Node-REDはハードウェアデバイス/APIおよびオンラインサービスを接続するためのツールです。
GUIでフローを作成することでイベントドリブンなアプリケーションを作成することができます。すごい便利そう!!
フロー例:
今回は家電のON/OFFを制御するのみ。
この末端のON/OFFのノードにコマンドを登録します。具体的には、iRKitのAPIを叩くcurlコマンド。
iRKitのcurl は以下参照。
IRKit - Open Source WiFi Connected Infrared Remote Controller
$ curl -i "http://x.x.x.x/messages" -H "X-Requested-With: curl" -d '{"freq":xx,"data":...}'
のような感じで実行できます。
試していないのですが、Node-RED 側でHTTPのRequestも飛ばせるようなので、おそらくそれでも動くと思います。
See Also
Alexa活用術
Siriの場合
同様にHomebridgeを使うことで対応可能です。