macでemacs -nwを使うとriskyと言われる

mac osxには標準でnw版のemacs 22が入っているのだが、init.elに23用のプラグインが入ってるとエラーになります。
こんなかんじで

signal(error ("Unknown keyword :risky"))
error("Unknown keyword %s" :risky)
custom-handle-keyword(package-load-list :risky t custom-variable)

Emacs.appに引数を付けて呼び出せば新しいバージョンを呼び出せます。

/Applications/Emacs.app/Contents/MacOS/Emacs -nw

しかしこれは間抜けだなあ。と思い、解決策を考えました。

which emacsでデフォルトemacsの場所をさがし、どこかにバイナリファイルを移動、その後ソースをダウンロードしてコンパイルすると新しいemacsがインストールされ、nwでもちゃんと開くようになります。
上書きはしないようなので、移動しないとダメです。

MySQLでrootなのにgrantコマンドが実行できない場合の対処法

rootでログインしてユーザーを増やそうと思ったら

mysql> grant all on *.* to "myuser"@"192.168.0.0/255.255.255.0";
ERROR 1045 (28000): Access denied for user 'root'@'localhost' (using password: NO)

と怒られた。

調べてみたら色々対処法があるみたいだが、とりあえずエラーログを見てみると

120801 9:43:15 [ERROR] Missing system table mysql.proxies_priv; please run mysql_upgrade to create it

言われた通りmysql_upgradeを実行すると

[root@localhost ~]# mysql_upgrade
Looking for 'mysql' as: mysql
Looking for 'mysqlcheck' as: mysqlcheck
Running 'mysqlcheck with default connection arguments
Running 'mysqlcheck with default connection arguments
mysql.columns_priv OK
mysql.db OK
mysql.func OK
mysql.general_log OK
mysql.help_category
error : Table upgrade required. Please do "REPAIR TABLE `help_category`" or dump/reload to fix it!
mysql.help_keyword
error : Table upgrade required. Please do "REPAIR TABLE `help_keyword`" or dump/reload to fix it!
mysql.help_relation OK
mysql.help_topic
error : Table upgrade required. Please do "REPAIR TABLE `help_topic`" or dump/reload to fix it!
mysql.host OK
mysql.proc
error : Table upgrade required. Please do "REPAIR TABLE `proc`" or dump/reload to fix it!
mysql.procs_priv OK
mysql.servers OK
mysql.tables_priv OK
mysql.time_zone OK
mysql.time_zone_leap_second OK
mysql.time_zone_name
error : Table upgrade required. Please do "REPAIR TABLE `time_zone_name`" or dump/reload to fix it!
mysql.time_zone_transition OK
mysql.time_zone_transition_type OK
mysql.user OK

Repairing tables
mysql.help_category OK
mysql.help_keyword OK
mysql.help_topic OK
mysql.proc OK
mysql.time_zone_name OK
Running 'mysql_fix_privilege_tables'...
OK

それ以外にも幾つかテーブルが足りなかったようで、作ってくれた。

再度grantしてみる

mysql> grant all on *.* to "myuser"@"192.168.0.0/255.255.255.0";
Query OK, 0 rows affected (0.00 sec)

今度はOK

入れたrpmが足りなかったのか、mysql_install_dbがおかしかったのか管理テーブルが足りなかったのが原因のようだ。

Facebook認証時、モバイル用ページを表示する

Oauth認証する際、APIに送るリクエストの末尾にdisplay="touch"をつけるとモバイル用のページが表示される。
通常のWEBページだったらdisplay=pageをつける(displayを付けないとこのページが採用されるようだ)

こんなかんじで

https://graph.facebook.com/oauth/authorize?response_type=code&client_id=xxxxxxxxxxxxxxxxx&redirect_uri=http%3A%2F%2Fhogehoge.com&scope=email%2Cphoto_upload%2Cpublish_stream%2Cuser_birthday&display=touch

エラーメッセージによれば、他にpopup, wapがあるようだ

Parameters: {"error"=>"invalid_request", "error_description"=>"Unsupported display: 'touch1'. Supported displays: popup, page, wap, touch"


facebook_oauthを使ってる場合、displayパラメタを付与できる作りになってないので、モンキーパッチを当てました。
facebook_oauth/lib/facebook_oauth/client.rb


15 15 client.auth_code.authorize_url(
16 16 :client_id => @application_id,
17 17 :redirect_uri => options[:callback] || @callback,
18 - :scope => options[:scope]
18 + :scope => options[:scope],
19 + :display => options[:display] || "page"
19 20 )
20 21 end

呼び出し側も修正

redirect_to client.authorize_url(:scope => 'emailとか', :display => "touch")


たぶんmoduleをオーバーライドするのが正解なんだけど、誰か方法教えてください><

FacebookのOAuth認証使ったアプリのテストを書く

facebook_oauth+Oauth2の場合

多分koalaでも基本一緒

Facebookへのトークン取得と自分の基本情報をfacebook_oauthから取得するようなプログラムのテストを書く場合

1.トークン取得
2.情報取得

の計2回Facebook APIを叩く必要がある。

まじめにやるならfoge_controller_test.rbに

require 'uri'
require 'net/http'

を追加して、FB側からのコールバック処理に

get :callback, { :code => "自分が使ってるホントのトークン"}

としてやれば動くはず。


ただ、アクセストークンは勿論固定ではないし、これだと自分自身のデータしか使えないのでユーザーごとに処理を変えるというようなことができない。

そこで、APIへのアクセスをダミー化してやる必要がある。

ダミー化するためにfakewebを使う

Gemfile

gem 'fakeweb'

テストコントローラーでfakewebを使う
hoge_controller_test.rb

require 'fakeweb'

先述の通りfacebook APIへの接続はトークン取得と情報取得2回発生するする。

なのでテストファイルには、まず1回目のアクセス用

FakeWeb.register_uri(:any, %r|https://graph\.facebook\.com/oauth|,
{:body => "access_token=12345", :status => ["200","OK"]}
)

https://graph.facebook.com/oauth/access_tokenがアクセストークン取得用URLだが、前方一致で/oauthまででおk

2回目のアクセス(データ取ってくる用)

FakeWeb.register_uri(:any, %r|https://graph\.facebook\.com/me|,
{:body => JSON.generate(:id => 11111111, :name=>'ほげほげ'),
:status => ["200","OK"],
:content_type => "application/json"}
)

https://graph.facebook.com/meがデータ取得用APIなので、トークン取得用と2回に分けて記述する必要がある。

ハマったのはパラメータの方で、facebookAPIは、リクエストに対してjson形式の値をbodyに入れて返すのだが、OAuth2がレスポンスヘッダに応じて処理を変えているため、明示的に:content_typeを指定してあげないといけない。
今回はfacebook_oauthを使ったが、たぶんこのへんはベースにOAuth2を使ってるkoalaでも一緒だと思う。

というか最近はfacebook_oauthは古くてkoalaが全盛だし、しかもさんざん調べてfakeweb使ったのにwebmockのほうがトレンドとかrubyってホント移り変わりが早い。


あとコントローラーに処理バリバリ書いてたのに、普通はモデルに書くもんだとかさ、どっかにそういうの書いておいてよマジで。

ruby-electricのend補完が効かない件

最近会社からmacを支給されたので、windowsからmacに鞍替えしました。

Windows(しかもXP)の頃はリッチなGUIでいたせりつくせりなAptanaでコーディングしていたわけですが、Macでも当然Aptana使おうと思ったら、なんかクールなギーグはEmacs!みたいな風潮があるらしく、別にクールでもギーグでもないんですが、転職活動の際のエディタ採用対策に、Emacsを使うことにした。


で、いろいろ機能拡張を入れてて、今はRailsで開発してるので、ruby-electricを入れたんだけど、説明にあるような、def 〜 end自動補完が動かない。

どうもこことか見てると、最新のバージョンで関数が足りないらしい。

困ったらstackoverflowということで、調べてみたらそのものスバリな記事が。

ということで、落としてきたruby-electric.elに

(defun ruby-insert-end ()
  "Insert \"end\" at point and reindent current line."
     (interactive)
     (insert "end")
     (ruby-indent-line t)
     (end-of-line))

を追加してバイトコンパイルしたら無事に使えるようになりました。

MySQLでDate関数同士を比較するときの注意

MySQLには日付の計算を行う関数がいくつかあって、例えば当日は


mysql> SELECT NOW();

  1. ---------------------+
NOW()
  1. ---------------------+
2012-04-23 16:26:11
  1. ---------------------+

1 row in set (0.00 sec)

前日は

mysql> SELECT NOW() - interval 1 day;

  1. ------------------------+
NOW() - interval 1 day
  1. ------------------------+
2012-04-22 16:28:17
  1. ------------------------+

1 row in set (0.00 sec)

で、これを日付だけ取り出したい場合、Date()を使う

mysql> SELECT date(NOW() - interval 1 day);

  1. ------------------------------+
date(NOW() - interval 1 day)
  1. ------------------------------+
2012-04-22
  1. ------------------------------+

1 row in set (0.00 sec)

単体で動かしているならこれで問題ないんだけど、Date()同士の引き算の結果がおかしくて軽くハマったので備忘録
まず同一月の引き算

mysql> SELECT DATE(NOW());

  1. -------------+
DATE(NOW())
  1. -------------+
2012-04-23
  1. -------------+

1 row in set (0.00 sec);

mysql> SELECT DATE(NOW() - INTERVAL 1 DAY);

  1. ------------------------------+
DATE(NOW() - INTERVAL 1 DAY)
  1. ------------------------------+
2012-04-22
  1. ------------------------------+

1 row in set (0.00 sec);

mysql> SELECT DATE(NOW()) - DATE(NOW() - INTERVAL 1 DAY);

  1. --------------------------------------------+
DATE(NOW()) - DATE(NOW() - INTERVAL 1 DAY)
  1. --------------------------------------------+
1
  1. --------------------------------------------+

1 row in set (0.00 sec)

同月同士なら全く問題なく計算できる。これが月をまたぐと全くおかしくなる。

mysql> SELECT DATE(NOW());

  1. -------------+
DATE(NOW())
  1. -------------+
2012-04-23
  1. -------------+

1 row in set (0.00 sec)

mysql> SELECT DATE(NOW() - INTERVAL 23 DAY);

  1. -------------------------------+
DATE(NOW() - INTERVAL 23 DAY)
  1. -------------------------------+
2012-03-31
  1. -------------------------------+

1 row in set (0.00 sec)

mysql> SELECT DATE(NOW()) - DATE(NOW() - INTERVAL 23 DAY);

  1. ---------------------------------------------+
DATE(NOW()) - DATE(NOW() - INTERVAL 23 DAY)
  1. ---------------------------------------------+
92
  1. ---------------------------------------------+

1 row in set (0.01 sec)

!?

どうも日付同士の演算をする場合、Date()だと年を365日、月を30 or 31 or 29として計算し直すのではなく、単純に年、月を10進数で+1桁としているようだ。
だからひと月前は30日ではなく、100、年は1000が足されたような格好になる。

なので日付どうしの計算を行う場合は、ちゃんとTO_DAYSを使いましょう。


mysql> SELECT TO_DAYS(NOW()) - TO_DAYS(NOW() - INTERVAL 23 DAY);

  1. ---------------------------------------------------+
TO_DAYS(NOW()) - TO_DAYS(NOW() - INTERVAL 23 DAY)
  1. ---------------------------------------------------+
23
  1. ---------------------------------------------------+

1 row in set (0.00 sec)

もしくはDATEDIFF

mysql> SELECT DATEDIFF(DATE(NOW()), DATE(NOW() - INTERVAL 23 DAY));

  1. ------------------------------------------------------+
DATEDIFF(DATE(NOW()), DATE(NOW() - INTERVAL 23 DAY))
  1. ------------------------------------------------------+
23
  1. ------------------------------------------------------+

1 row in set (0.00 sec)

使用頻度はどっちが高いんだろう。

MySQLのEVENT SCHEDULERを毎日定時実行する方法

備忘録的に。

delimiter $$
DROP EVENT IF EXISTS hogehoge $$
CREATE EVENT hogehoge
ON SCHEDULE EVERY 1 DAY
STARTS '2012-04-18 03:00:00'
DO
BEGIN
  この中に実行するSQLを記述
END$$
delimiter ;

ON SCHEDULE EVERY 1 DAY
STARTS '2012-04-18 03:00:00'

で、2012/04/18のAM3時から一日毎に毎時3時実行されます。