rubyとcrontabで毎朝、休講情報を取得するプログラムを作成した話
はじめに
私は、学内アルバイトとして、TA(Teaching Assistant)をしている。基本的な業務は、簡単なエクセルの使い方やワードの使い方などを教えている。 しかし、TAは授業を履修していないため、休講情報の通知が来ない。
休講情報はベーシック認証があるサーバに存在しており、自動で取得し通知することを考えた。
ロジック
--- ruby ---
- 外部からアクセス可能(basic認証)なウェブサイトの休講情報を取得する
- 整形させる
- 当日の休講情報を抽出/出力
crontabで、上記のプログラムを毎朝実行し、メールする。 これらを、ウェブサービスを公開するために借りたVPSにおいておく。
http://hagetak.hatenablog.com/entry/2015/02/20/232004
書いてみた。
require 'nokogiri' require 'mechanize' agent = Mechanize.new agent.add_auth('http://www.gakkounowebsite.info/', 'userid', 'password') @page = agent.get('http://www.gakkounowebsite.info/?page_id=1028') @content = @page.search('.entry-content') @class_datas = [] # 検索用 => "6月12日"という文字列を検索するために b = Time.now @today = "#{b.month}月#{b.day}日" # <p>6月12日 情報倫理<br>\n 教室:1201教室... </p> # <p>6月12日 財務諸表<br>\n 教室:1203教室... </p> # => ['6月12日 情報倫理...', '6月12日 財務諸表'] @content.xpath("//p").each do |c| @class_datas << c end a = [] @sending_datas = [] # [0] => date # [!0] => className, teacher, remarks # @class_datas[0] => "6月22日(月)\n 2限:情報演習・基礎 \n 担当:斉藤先生 \n 補講:課題指示あり" # a[0] => ["6月22日(月)", "2限:情報演習・基礎", "担当:斉藤先生", "補講:課題指示あり"] @class_datas.each do |info| a << info.text.split("\n") end # 本日休講の項目を取得 a.each do |s| s[0].tr!("0-9", "0-9") @sending_datas << s if(s[0].to_s.match(@today)) end puts '休講情報はありません' unless @sending_datas @sending_datas.each do |s| puts '*** ' * 10 puts s end
今こうしてみると、読みづらく、気持ち悪いね。整形作業に手間がかかってる感じ。もう少し簡単にできないだろうか...。
crontabの設定
crontabについて学んだことは、後日記事にする。 さて、このプログラム(fetch_class_info.rb)をcrontabで動かしたいと思う。
いかのプログラムを書いて、動かしている。
35 7 * * * /home/hagetak/.rbenv/shims/ruby /home/hagetak/cron/fetch_class_info.rb | mail -s `echo $(date +'\%Y/\%m/\%d')休講情報` your_email_address@domain.com
一つ一つ見てみると、わかるだろう。
minites hour * * * [実行するプログラム]
という感じで、この例では、毎日7時35分に実行するプログラムだ。所有者・実行者が違うと、PATHが通っていない可能性があるので、絶対参照でプログラムを実行させることにした。
実行させたい大本のプログラム(ruby だったり, pythonだったり...)は、whichコマンドで確認することができる。
> which ruby => /home/hagetak/.rbenv/shims/ruby
ruby yourprogram.rb
で実行できるので、rubyファイルは絶対参照で記述。
次のステップは、少しややこしい。(件名を日本語/変更したくない場合はこの処理は飛ばして良い)
mail -s
echo $(date +'\%Y/\%m/\%d')休講情報
your_email_address@domain.com
実行した結果を mail コマンドに受け渡し、送信するというモノだ。
echo $(date +'\%Y/\%m/\%d')休講情報
これは、いつの休講情報かわからないために追加したもの。
crontabのshに問題があるため、dateコマンド内の%はバックスラッシュでエスケープすること
この処理で引っかかって、1日ずっと考えていた...。
dateコマンド と crontab の コマンドライン中の %(パーセント)記号 - keigoiの日記
さて、これらをまとめると、以下に置き換えられるだろう。
result of your program | mail -s "件名" your_email_address@domain.com
cron処理結果を、subjectを日本語にしてメールする方法 | Web開発者の備忘録
知見
- いきなり毎朝...で設定すると気が遠くなるので、以下に変更すると良い(毎分)
*/1 * * *
- メールが届かない!ってときは、次のコマンドを打つと出ている
- 件名とかいらない。ってときは簡略なものでできる
MAILTO="your_email_address@domain.com" */2 * * * * /usr/bin/ruby /Users/hagetak/cron/fetch_class_info.rb
Mac版無償提供の「Visual Studio Code」を早速使ってみた感想
はじめに
朝、起きたらTLが「Visual Studio Code」の一色になっていた。ほほう、あのマイクロソフト株式会社がMacOS向けにエディタを提供したのか。
マイクロソフトは囲い込みが印象強いが、今回の公開で結構印象が変わった。たぶん、TLにいる皆さんもそう思っているのではないか。
気になったので早速ダウンロードして、使ってみた。
ダウンロード
次のサイトからダウンロードできる。該当するOSを選択してください。
https://code.visualstudio.com/Download
Google で Visual Studio って検索しても多分出てこないと思う。自分もそれで苦戦した。
使ってみた。
前回の記事にあるフィボナッチ数列のプログラムを書いてみた。
感想
コード補完(2/5)
まだまだコード補完が甘いな、というのが印象。補完が全てじゃないけど、補完の強さが一つの指標になると思っている。
まだまだ出始め、プレビュー版であるので今後は様々なプラグインやパッケージが出てくることを祈りましょう。
ものによっては、コード補完が強いらしい。
Visual Studio Code、どれくらい補完が速いかご覧ください。 pic.twitter.com/pRwaaPJpbI
— mattn (@mattn_jp) 2015年4月29日
軽さ(5/5)
これは驚いた。すごく軽い。コード補完プラグインがない分軽いのは当たり前なんだが、すごく軽いよね。(軽さとコード補完の強さはトレードオフ関係にあると思う。)ちょっとしたコードを書くときは、低補完でさくさくと書いていくのが良いんじゃない?
見た目(4/5)
クール。これもカスタマイズできるはず。今後出てくるはず。
操作感(3/5)
ここが結構重要で、今まで一番上・一番下にいくショートカットキーは、Command + ↕だったんだが、これができず、操作がしづらい。
基本、Emacsのコマンドは使えるっぽいので、(Ctrl - a, Ctrl - e)慣れている人はすごく使いやすいと思う。自分はあまりコマンドを知らず、慣れてないので違和感がすごくある。
さいごに
自分が使いこなせていない感がありまくり。
今後、Visual Studio Code がどう発展していくかにより、メインエディタが決まってくる。
本来、こうやって任せっきりにするのが素人なんだよね。なら、自分で使いやすくしよう!ってのがプロだよね...。
なんか貢献できることがあれば貢献していきたいな。
Emacs実践入門 ?思考を直感的にコード化し、開発を加速する (WEB+DB PRESS plus)
- 作者: 大竹智也
- 出版社/メーカー: 技術評論社
- 発売日: 2012/03/07
- メディア: 単行本(ソフトカバー)
- 購入: 22人 クリック: 396回
- この商品を含むブログ (1件) を見る
フィボナッチ数をjavascriptで算出してみた。
はじめに
急にフィボナッチ数を解きたい!と思った。ということで、書いてみた。
オリジナル:フィボナッチ数(JavasScript)
- 5分で考えた、書いたコード
function fibonacci(p, n, max_num){ if(n > max_num){ return 0; } console.log(n); return fibonacci(n, n + p, max_num); } fibonacci(0, 1, 100)
本当にパッと思いついたもので、フィボナッチ数列の定義(アルゴリズム上での公式)を無視している。 このmax_numというのは、max_numまでの数値を算出するというモノ。普通は何番目のが欲しいか、ってのが引数になるよね。
引数の 0, 1 がきもいので、ちょっと変えた。
function fibonacci(max_num, p, n) { if(p === undefined) { p = 0;} if(n === undefined) { n = 1;} if(n > max_num) { return 0; } console.log(n); return fibonacci(max_num, n, n + p) } fibonacci(100)
デフォルト値を入力する感じ、ifが多くてパフォーマンスが落ちるかな。(この程度は気にしないレベルだと思うけど)
定義?を知った上で書きなおしてみる。
function fibonacci(n) { if(n < 2) { return 0; } else { return fibonacci(n-1) + fibonacci(n-2); } }
これが現実的な解答であるんだが、パフォーマンスがすごく悪いよね。俺のほうが早くてびっくりした。(厳密には違う解法だけど!!!)
メモ化を使ってみる
メモ化とは、一度計算した数値を配列に保存しておくことで、すぐに呼び出せるよね!ってやつ。
for で済ませるパターン
var _fibs = [0, 1]; function fib(n) { for(var i = _fibs.length; i <= n; i++){ _fibs[i] = _fibs[i-1] + _fibs[i-2]; } } function fibs(n) { fib(n); return _fibs.slice(0, n + 1); } fibs(10)
これでオッケーかな。グローバル変数を使うのは嫌なんだが...しょうがないかな。
次の記事には、「メモ化」で「再帰呼び出し」パターンのがある。
さいごに
今まで避けてきた再帰呼び出しを実際にやってみた。
意外と簡単にロジックが組め、すぐにコードで表現できるようになった。今回は少し、デフォルト値とか工夫してみた。こういうのも勉強になった。
フィボナッチ数列のような、数学が好きなので、次回もこういうやつをやってみたい。それと、Rubyで書きなおす。
頑張るぞぉ
404 Blog Not Found:アルゴリズム百選 - フィボナッチ数列にO()を学ぶ
波紋と螺旋とフィボナッチ: 数理の眼鏡でみえてくる生命の形の神秘
- 作者: 近藤滋
- 出版社/メーカー: 学研メディカル秀潤社
- 発売日: 2013/09/13
- メディア: 単行本
- この商品を含むブログ (5件) を見る
- 作者: サイモンシン,青木薫
- 出版社/メーカー: 新潮社
- 発売日: 2006/05/30
- メディア: 文庫
- 購入: 105人 クリック: 1,697回
- この商品を含むブログ (585件) を見る
動的に追加したDOM要素にイベントを設定する!
はじめに
持ち駒カウンターを作った。jQueryで操作しているので、DOMを動的に追加などをするのだが、動的に追加したDOM要素にイベントが上手く設定されなかった。
コード例
<div> <button class="addItemButton"> </button> <div class="itemList"> <li class="remove"> 追加エリア </li> <!-- 以下から追加 --> </div> </div>
$('.addItemButton').on('click', function(){ $('.itemList').append('<li> class="remove">Hello </li>') }) $('.remove').on('click', function(){ $(this).remove() })
解決法
jQuery - 動的に追加したDOM要素にイベントハンドラを設定する - Qiita
JavaScript - 動的に追加されるDOM要素に対応する方法あれこれ - Qiita
この書き方は、これらの記事と同様で、onを使っている。引数が足らないが、これらと同じ形式にしてもイベント要素が追加されなかった。
今回、以下の様な書き方で実現できた。
$(document).on('click', '.remove', funciton(){ $(this).remove() })
原因はわからない。普段は、上のような書き方でできるのだが、今回引っかかったのでメモとしておく。
JavaScript本格入門 ?モダンスタイルによる基礎からAjax・jQueryまで
- 作者: 山田祥寛
- 出版社/メーカー: 技術評論社
- 発売日: 2010/11/27
- メディア: 大型本
- 購入: 29人 クリック: 673回
- この商品を含むブログ (51件) を見る
- 作者: 蒲生睦男
- 出版社/メーカー: シーアンドアール研究所
- 発売日: 2013/01/19
- メディア: 単行本(ソフトカバー)
- クリック: 2回
- この商品を含むブログ (4件) を見る
『ソースコードを読む技術』を読んでみた
本書の目的
を対象にしている。この2つも「スキルアップをするため」に「オープンソースを読む」って感じだと思うので、中級者が次の壁を乗り越えるために必要とする技術、「ソースコードを読む技術」を学ぶのが目的である。
- 作者: 高木信尚
- 出版社/メーカー: 技術評論社
- 発売日: 2010/06/11
- メディア: 単行本(ソフトカバー)
- 購入: 2人 クリック: 151回
- この商品を含むブログ (14件) を見る
構成
- プログラムを読む理由を知る
- プログラムを読む素養を学ぶ
- プログラムの読み方のコツを学ぶ
- printfを例に筆者とソースコードを読んでみる
感想
プログラムの行間を読むということは、様々な思考を巡らせて読むことである。以下の例では、「barとはなんだろうか」、「戻り値は何が戻ってくるのか」、「型的に大丈夫なのか」など予測して読むことである。ここは、経験が重要になってくるのかな、と思った。
void main(int x) { if(x > 1 || x < 10) { bar(x); } }
本書では、「C」, 「C++」, 「C#」, 「Java」を主に取り上げていて、これらの経験があればスラスラと読めるだろう。授業で「C」を利用したレベルの自分でもまぁまぁ理解することができた。
3は、簡単に流し読みした程度なので、あまり知識としては定着していない。ソースコードを読むために、「grep」や「クラス図」など様々なツールを利用すると捗るということらしい。
4は、「printf」。Cやっているとこれはよく出るのだが、今回は興味がなかったのでパスをすることにした。興味がある、使っている言語のオープンソースを読むほうがモチベーションが保て、テクニックなどを知れるため技術力の向上になるだろう。(printfは基礎というか、素養として身につけるべきであるが...)
- 作者: 高橋麻奈
- 出版社/メーカー: ソフトバンククリエイティブ
- 発売日: 2012/09/03
- メディア: 単行本
- この商品を含むブログ (4件) を見る
- 作者: 紀平拓男,春日伸弥
- 出版社/メーカー: ソフトバンククリエイティブ
- 発売日: 2011/03/30
- メディア: 単行本
- 購入: 15人 クリック: 255回
- この商品を含むブログ (31件) を見る
Ruby:標準出力(p, puts, print)の違いを考察する
はじめに
先日、paizaの最終問題をクリアした。というのも、フォロワーさんの協力があったからだ。今まで曖昧だったRubyの標準出力を改めて学ぶ。
以下の変数を用い、各コマンド(関数)の出力結果を調べ、特徴を述べる。
2.1.1 :001 > str = "STR" => "STR" 2.1.1 :002 > int = 100 => 100 2.1.1 :003 > array = ["a", "b", "c", "d", "e"] => ["a", "b", "c", "d", "e"] 2.1.1 :004 > array2 = [["a","b"], ["c", "d"], ["e", "f"]] => [["a", "b"], ["c", "d"], ["e", "f"]] 2.1.1 :008 > hash = {:john=>{name:"john", age:21}, :michael => {name:"michael", age:20}} => {:john=>{:name=>"john", :age=>21}, :michael=>{:name=>"michael", :age=>20}}
p
pメソッドは、引数のオブジェクトを分かりやすい文字列にして標準出力に出力します。
わかりやすい文字列とはなんだろう。上の変数をすべて出力させる。
2.1.1 :012 > p => nil 2.1.1 :013 > p str "STR" => "STR" 2.1.1 :014 > p int 100 => 100 2.1.1 :015 > p array ["a", "b", "c", "d", "e"] => ["a", "b", "c", "d", "e"] 2.1.1 :016 > p array2 [["a", "b"], ["c", "d"], ["e", "f"]] => [["a", "b"], ["c", "d"], ["e", "f"]] 2.1.1 :017 > p hash {:john=>{:name=>"john", :age=>21}, :michael=>{:name=>"michael", :age=>20}} => {:john=>{:name=>"john", :age=>21}, :michael=>{:name=>"michael", :age=>20}}
特徴
- 改行を含まない
- 戻り値も返す
puts
putsメソッドは、引数のオブジェクトを文字列に変換し、改行を加えて標準出力に出力します。
2.1.1 :019 > puts str STR => nil 2.1.1 :020 > puts int 100 => nil 2.1.1 :021 > puts array a b c d e => nil 2.1.1 :023 > puts array2 a b c d e f => nil 2.1.1 :024 > puts hash {:john=>{:name=>"john", :age=>21}, :michael=>{:name=>"michael", :age=>20}} => nil
特徴
- 戻り値がnil
- 改行を含む
- 配列は要素1つ出力して改行を含む
- str が文字列で出力されない
printメソッドは、引数のオブジェクトを文字列にして標準出力に出力します。
2.1.1 :035 > print str STR => nil 2.1.1 :036 > print int 100 => nil 2.1.1 :037 > print array ["a", "b", "c", "d", "e"] => nil 2.1.1 :038 > print array2 [["a", "b"], ["c", "d"], ["e", "f"]] => nil 2.1.1 :039 > print hash {:john=>{:name=>"john", :age=>21}, :michael=>{:name=>"michael", :age=>20}} => nil
特徴
- 戻り値はnil
爆弾問題の出力結果について
paizaの爆弾問題は、以下の出力結果が必要になる。
1 2 3 4 5 6 7 8 9
この出力結果になるよう、それぞれの関数で挑戦してみる。
2.1.1 :064 > array.each do |a| 2.1.1 :065 > p a 2.1.1 :066?> end [1, 2, 3] [4, 5, 6] [7, 8, 9] => [[1, 2, 3], [4, 5, 6], [7, 8, 9]] 2.1.1 :067 > array.each do |a| 2.1.1 :068 > puts a 2.1.1 :069?> end 1 2 3 4 5 6 7 8 9 => [[1, 2, 3], [4, 5, 6], [7, 8, 9]] 2.1.1 :070 > array.each do |a| 2.1.1 :071 > print a 2.1.1 :072?> end [1, 2, 3][4, 5, 6][7, 8, 9] => [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
joinが必要とフォロワーさんから教わり...
2.1.1 :052 > array.each do |a| 2.1.1 :053 > p a.join(' ') 2.1.1 :054?> end "1 2 3" "4 5 6" "7 8 9" => [[1, 2, 3], [4, 5, 6], [7, 8, 9]] 2.1.1 :055 > array.each do |a| 2.1.1 :056 > puts a.join(' ') 2.1.1 :057?> end 1 2 3 4 5 6 7 8 9 => [[1, 2, 3], [4, 5, 6], [7, 8, 9]] 2.1.1 :058 > array.each do |a| 2.1.1 :059 > print a.join(' ') 2.1.1 :060?> end 1 2 34 5 67 8 9 => [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
配列 [1, 2, 3]、[4, 5, 6]または、[7, 8, 9]をjoinする(くっつける)と、こういう出力になるのか。今回も学ぶことがすごく多かったな〜
まとめ
今回わかった特徴を簡単に表にまとめてみる。
コマンド | 戻り値 | 出力結果 | 改行 |
---|---|---|---|
p | 有 | わかりやすい文字列 | 無 |
puts | nil | 文字列 | 有 |
nil | 文字列 | 無 |
※ 汚いテーブルでごめんね。出力結果はせめてコマンドの隣か一番右だよね。
オープンソースを読むことも必要だと思い、rubyのソースコードを読んでみた。
今更知ったけど、Cで書かれているのね。元は。わからないけど Ruby -> C -> 出力 みたいな手順なのかな。Rubyのオープンソースを読むのはCを結構理解していないとダメなので。ぱっとみ、関数ポインタとかあって分からなかった。Cの知識を増やそう。
同時に、RailsならRubyのソースコードでしょう。中身は。まずはRailsのオープンソースを読む。
- 作者: 高橋征義,後藤裕蔵,まつもとゆきひろ
- 出版社/メーカー: ソフトバンククリエイティブ
- 発売日: 2013/06/04
- メディア: 単行本
- この商品を含むブログ (33件) を見る
- 作者: まつもとゆきひろ,David Flanagan,卜部昌平(監訳),長尾高弘
- 出版社/メーカー: オライリージャパン
- 発売日: 2009/01/26
- メディア: 大型本
- 購入: 21人 クリック: 356回
- この商品を含むブログ (129件) を見る
JavaScirpt:prototypeの存在意義
はじめに
先日、GCについて調べたところ、JavaScriptのprototypeに関する記事があり、存在意義を知ることができた。今回はそれをまとめてみる。
ちなみにGCとは、ガーベージコレクションのこと。
1. 具体例
var Human = function(name) { this.name = name; this.tell = function(){ console.log("My name is", this.name); }; } var john = new Human("John") john.tell() // => "My name is john" var elizabeth = new Human("Elizabeth") elizabeth.tell() // => "My name is Elizabeth"
上記のコードは見れば分かるだろう。さてこれからだ!
2. john君は叫びたい
john君が叫びたいらしい、なら叫ばせよう。単純に上位のHumanにshout()を追加すればいいでしょう。
var Human = function(name) { this.name = name; this.tell = function(){ console.log("My name is", this.name); }; this.shout = function(){ console.log("YEEEEEEEEAAAAAAAAAAAAHHHHHH"); }; } var john = new Human("John"); john.tell(); // => "My name is john" john.shout(); // => "YEEEEEEEEAAAAAAAAAAAAHHHHHH"
よし、これでよいでしょう。じゃないんです!
3. エリザベスちゃんも叫んじゃう
var Human = function(name) { this.name = name; this.tell = function(){ console.log("My name is", this.name); }; this.shout = function(){ console.log("YEEEEEEEEAAAAAAAAAAAAHHHHHH"); }; } var elizabeth = new Human("Elizabeth"); elizabeth.tell(); // => "My name is Elizabeth" elizabeth.shout(); // => "YEEEEEEEEAAAAAAAAAAAAHHHHHH"
叫んじゃった。これだとjohnくんもびっくり。
Elizabethはおしとやかに、johnくんはキチガイに
叫びたいjohnくんはキチガイ。キチガイは1人でいい。そういうときに、prototypeが使えるんです。
var Human = function(name) { this.name = name; this.tell = function(){ console.log("My name is", this.name); }; } var john = new Human("John"); john.tell(); // => "My name is john" john.prototype = { shout: function(){ console.log("YEEEEEEEEAAAAAAAAAAAAHHHHHH"); } } john.prototype.shout(); // => "YEEEEEEEEAAAAAAAAAAAAHHHHHH"
エリザベスも叫んじゃうんじゃない?
var elizabeth = new Human("Elizabeth"); elizabeth.prototype.shout() // => "Uncaught TypeError: Cannot read property 'shout' of undefined.
エラーはいたのでエリザベスは叫べなかった。
現段階ではjohnくんだけが叫ぶことが可能である。これがprototypeだ。
5. prototypeの使いドコロ
このようにだれでも叫べるようにしたら、メモリを浪費してしまう。特定の人(オブジェクト)だけ追加したいってときは、prototypeで追加するようにしよう!
- 作者: David Flanagan,村上列
- 出版社/メーカー: オライリージャパン
- 発売日: 2012/08/10
- メディア: 大型本
- 購入: 12人 クリック: 252回
- この商品を含むブログ (18件) を見る
開眼! JavaScript ―言語仕様から学ぶJavaScriptの本質
- 作者: Cody Lindley,和田祐一郎
- 出版社/メーカー: オライリージャパン
- 発売日: 2013/06/19
- メディア: 単行本(ソフトカバー)
- この商品を含むブログを見る