hagetak's blog

どうも、はげたかです。

rubyとcrontabで毎朝、休講情報を取得するプログラムを作成した話

はじめに

私は、学内アルバイトとして、TA(Teaching Assistant)をしている。基本的な業務は、簡単なエクセルの使い方やワードの使い方などを教えている。 しかし、TAは授業を履修していないため、休講情報の通知が来ない。

休講情報はベーシック認証があるサーバに存在しており、自動で取得し通知することを考えた。

ロジック

--- ruby ---

  1. 外部からアクセス可能(basic認証)なウェブサイトの休講情報を取得する
  2. 整形させる
  3. 当日の休講情報を抽出/出力

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 * * *

  • メールが届かない!ってときは、次のコマンドを打つと出ている

mail

  • 件名とかいらない。ってときは簡略なものでできる
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

GoogleVisual Studio って検索しても多分出てこないと思う。自分もそれで苦戦した。

使ってみた。

前回の記事にあるフィボナッチ数列のプログラムを書いてみた。

感想

コード補完(2/5)

まだまだコード補完が甘いな、というのが印象。補完が全てじゃないけど、補完の強さが一つの指標になると思っている。

まだまだ出始め、プレビュー版であるので今後は様々なプラグインやパッケージが出てくることを祈りましょう。

ものによっては、コード補完が強いらしい。

軽さ(5/5)

これは驚いた。すごく軽い。コード補完プラグインがない分軽いのは当たり前なんだが、すごく軽いよね。(軽さとコード補完の強さはトレードオフ関係にあると思う。)ちょっとしたコードを書くときは、低補完でさくさくと書いていくのが良いんじゃない?

見た目(4/5)

クール。これもカスタマイズできるはず。今後出てくるはず。

操作感(3/5)

ここが結構重要で、今まで一番上・一番下にいくショートカットキーは、Command + ↕だったんだが、これができず、操作がしづらい。

基本、Emacsのコマンドは使えるっぽいので、(Ctrl - a, Ctrl - e)慣れている人はすごく使いやすいと思う。自分はあまりコマンドを知らず、慣れてないので違和感がすごくある。

さいごに

自分が使いこなせていない感がありまくり。

今後、Visual Studio Code がどう発展していくかにより、メインエディタが決まってくる。

本来、こうやって任せっきりにするのが素人なんだよね。なら、自分で使いやすくしよう!ってのがプロだよね...。

なんか貢献できることがあれば貢献していきたいな。

Emacs実践入門 ?思考を直感的にコード化し、開発を加速する (WEB+DB PRESS plus)

Emacs実践入門 ?思考を直感的にコード化し、開発を加速する (WEB+DB PRESS plus)

フィボナッチ数をjavascriptで算出してみた。

はじめに

急にフィボナッチ数を解きたい!と思った。ということで、書いてみた。

f:id:hagetak:20150429131831p:plain

オリジナル:フィボナッチ数(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()を学ぶ

フェルマーの最終定理 (新潮文庫)

フェルマーの最終定理 (新潮文庫)

動的に追加したDOM要素にイベントを設定する!

はじめに

持ち駒カウンターを作った。jQueryで操作しているので、DOMを動的に追加などをするのだが、動的に追加したDOM要素にイベントが上手く設定されなかった。

hagetak.hatenablog.com

コード例

<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まで

JavaScript本格入門 ?モダンスタイルによる基礎からAjax・jQueryまで

はじめて学ぶ enchant.jsゲーム開発

はじめて学ぶ enchant.jsゲーム開発

『ソースコードを読む技術』を読んでみた

本書の目的

を対象にしている。この2つも「スキルアップをするため」に「オープンソースを読む」って感じだと思うので、中級者が次の壁を乗り越えるために必要とする技術、「ソースコードを読む技術」を学ぶのが目的である。

プログラマーのためのソースコードを読む技術

プログラマーのためのソースコードを読む技術

構成

  1. プログラムを読む理由を知る
  2. プログラムを読む素養を学ぶ
  3. プログラムの読み方のコツを学ぶ
  4. printfを例に筆者とソースコードを読んでみる

感想

プログラムの行間を読むということは、様々な思考を巡らせて読むことである。以下の例では、「barとはなんだろうか」、「戻り値は何が戻ってくるのか」、「型的に大丈夫なのか」など予測して読むことである。ここは、経験が重要になってくるのかな、と思った。

void main(int x) {

  if(x > 1 || x < 10) {
    bar(x);
  }
}

本書では、「C」, 「C++」, 「C#」, 「Java」を主に取り上げていて、これらの経験があればスラスラと読めるだろう。授業で「C」を利用したレベルの自分でもまぁまぁ理解することができた。

3は、簡単に流し読みした程度なので、あまり知識としては定着していない。ソースコードを読むために、「grep」や「クラス図」など様々なツールを利用すると捗るということらしい。

4は、「printf」。Cやっているとこれはよく出るのだが、今回は興味がなかったのでパスをすることにした。興味がある、使っている言語のオープンソースを読むほうがモチベーションが保て、テクニックなどを知れるため技術力の向上になるだろう。(printfは基礎というか、素養として身につけるべきであるが...)

プログラミングの宝箱 アルゴリズムとデータ構造 第2版

プログラミングの宝箱 アルゴリズムとデータ構造 第2版

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

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 文字列
print nil 文字列

※ 汚いテーブルでごめんね。出力結果はせめてコマンドの隣か一番右だよね。

オープンソースを読むことも必要だと思い、rubyソースコードを読んでみた。

今更知ったけど、Cで書かれているのね。元は。わからないけど Ruby -> C -> 出力 みたいな手順なのかな。Rubyオープンソースを読むのはCを結構理解していないとダメなので。ぱっとみ、関数ポインタとかあって分からなかった。Cの知識を増やそう。

同時に、RailsならRubyソースコードでしょう。中身は。まずはRailsオープンソースを読む。

Kernel - Rubyリファレンス

プログラミング言語 Ruby

プログラミング言語 Ruby

JavaScirpt:prototypeの存在意義

はじめに

先日、GCについて調べたところ、JavaScriptのprototypeに関する記事があり、存在意義を知ることができた。今回はそれをまとめてみる。

ちなみにGCとは、ガーベージコレクションのこと。

utage.headwaters.co.jp

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で追加するようにしよう!

JavaScript 第6版

JavaScript 第6版

開眼!  JavaScript ―言語仕様から学ぶJavaScriptの本質

開眼! JavaScript ―言語仕様から学ぶJavaScriptの本質