Mouse(Moose)のRoleにはBUILDメソッドを書くべきではないんだね
下記のようなソースがあった。
Sasakure.pm
package Sasakure; use Mouse; with 'SasaRole'; __PACKAGE__->meta->make_immutable; no Mouse; 1;
SasaRole.pm
package SasaRole; use Mouse::Role; no Mouse::Role; sub BUILD { my $self = shift; warn "sasarole"; #「sasarole」 がエラーログに吐かれる } 1;
Moose初心者の僕は、Sasakure.pmでもBUILDメソッド使いたいな〜 なんて軽い気持ちで
Sasakure.pmにBUILDメソッドを追加したら、SasaRole.pmのBUILDメソッドが実行されなくなった。
Sasakure.pm
package Sasakure; use Mouse; with 'SasaRole'; __PACKAGE__->meta->make_immutable; no Mouse; sub BUILD { # 実行される my $self = shift; warn "sasakure"; #「sasakure」 がエラーログに吐かれる } 1;
SasaRole.pm
package SasaRole; use Mouse::Role; no Mouse::Role; sub BUILD { # 実行されない my $self = shift; warn "sasarole"; #「sasarole」 はエラーログに出ない } 1;
よくよく考えると、withすることでSasaRole.pmのプロパティやらメソッドはSasakure.pmに継承されている。
もちろんSasaRole.pmのBUILDメソッドも、、、
んでSasakure.pmではwithした後に、BUILDメソッドを定義している。。。
もしかして、同じメソッド名はオーバーライドされちゃうんじゃない?
上と同じだけどSasakure.pm
package Sasakure; use Mouse; with 'SasaRole'; # SasaRoleを我が一部とする もちろんBUILDメソッドも __PACKAGE__->meta->make_immutable; no Mouse; sub BUILD { # SasaRoleにもBUILDメソッドあったけど、こっちを使おうぜ my $self = shift; warn "sasakure"; #「sasakure」 がエラーログに吐かれる } 1;
ということは、そもそもRoleモジュールでBUILDメソッドは使うべきではないよね。
BUILDARGS や DEMOLISH も同じだろうから気を付けよう。
CGI::Application::DispatchとMouse(Moose)を使った時にハマったこと
CGI::Application::Dispatchで下記のようにargs_to_newを使うと、
実行するモジュールへの引数が指定出来る。
index.cgi
#!/usr/bin/perl use strict; use warnings; use CGI::Application::Dispatch; CGI::Application::Dispatch->dispatch( prefix => 'Sasakure', table => [ '' => { app => 'Blog', rm => 'posts' }, ], args_to_new => { PARAMS => { foo => 'bar' }, } ); exit;
Sasakure/Blog.pm
package Sasakure::Blog; use strict; use warnings; use base 'CGI::Application'; sub posts { $self = shift; warn $self->PARAMS->{foo}; # エラーログに「bar」が吐かれる。 } 1;
よーし!ディスパッチはできたから、最近かじっているMouseを利用してみよう!
という時に思わぬ事件。。
下記のように書いたらindex.cgiからパラメータが受け取れなくなってしまった。
Sasakure/Blog.pm
package Sasakure::Blog; use base 'CGI::Application'; use Mouse; __PACKAGE__->meta->make_immutable; no Mouse; sub posts { $self = shift; warn $self->PARAMS->{foo}; # そんなんねーよとエラー } 1;
原因はnewにあった。
MooseやMouseで__PACKAGE__->meta->make_immutable;をすると、newというコンストラクタは呼ばれなくなる。
代わりにBUILDという名前のメソッドがその役割を担ようになる。
CGI::Application::Dispatchでは,コールするモジュールのnewメソッドとmode_paramメソッドを実行しようとする。
んで、そのときにargs_to_newで渡されたパラメータを受け取る。
それを1行で済ませるのが、use base qw/CGI::Application/;だ。
継承することで、newメソッドとか書く必要がなくなる。
でも何度も言うようにMouseでmake_immutableすると、、newが呼ばれなくなる。
というわけで下記のように書くことで、無事index.cgiからパラメータを受け取れるようになった。
Sasakure/Blog.pm
package Sasakure::Blog; #use base 'CGI::Application'; use Mouse; # index.cgiからのパラメータをしまう場所を用意 has 'params' => ( is => 'rw', isa => 'ArrayRef[Str]', ); __PACKAGE__->meta->make_immutable; no Mouse; sub BUILD { # newに代わるメソッドでパラメータを受け取る my $self = shift; my ( $dispatch_args, ) = @_; $self->{params} = $dispatch_args->{PARAMS}; } sub mode_param { # これ使わなくても用意しとかないとDispatchがエラー出しよる my $self = shift; return $self; } sub posts { $self = shift; warn $self->params->foo; # 無事、エラーログに「bar」が吐かれる。 } 1;
MySQLでテーブルサイズを調べる方法のメモ
▼全てのテーブルサイズをGB(ギガバイト)で取得
SELECT SUM(data_length)/1024/1024/1024 as db_size_GB FROM information_schema.tables WHERE table_schema='データベース名';
▼特定のテーブルサイズをMB(メガバイト)で取得
SELECT SUM(data_length)/1024/1024 as db_size_MB FROM information_schema.tables WHERE table_schema='データベース名' AND table_name='テーブル名';
▼インデックスのサイズを調べる
data_lengthをindex_lengthにすればok
ScalaでJavaのListをforにぶっこんだら怒られた
エラーはこんな感じ。
value foreach is not a member of java.util.List[String]
for(foreach)はJavaのListを扱えないんですって。
じゃあどうしたらforで扱えるのさ?
型変換を行えば良いらしい。
まずは必要なモジュールをインポート。
import scala.collection.JavaConversions._
そして
for (scala_string <- asScalaBuffer(java_list)) { << 省略 >> }
できたーーー!
他のメソッドはこちらを参考にどうぞ
http://www.scala-lang.org/api/rc/scala/collection/JavaConversions$.html
ちなみに、asList()でも出来るけど、廃止予定らしいのでwarning出ると思います。
Entity-Attribute-Valueモデル
ECパッケージ Magento で使われているEAVモデルについて、自分なりに理解できているか確認の意味も込めてまとめます。
誤りなど気づいた方がいらしたら、是非つっこんでください。
まずよくあるユーザーテーブル
▼customer_table
id | name | birthday | address |
---|---|---|---|
1 | sasakure | 1984/12/03 | tokyo shibuya |
2 | tarou | 2002/01/22 | kanagawa kawasaki |
これをEAVモデルにすると下記のようになります。
まずはEntity
▼entities_table
id |
---|
1 |
2 |
Entityは「実態」とか「実在」という意味です。
この場合「ユーザ」を表します。
最低でもidだけあればEntityとして充分です。
次にAttribute
▼attributes_table
id | attributes_name |
---|---|
1 | name |
2 | birthday |
3 | address |
Attributeは「属性」という意味です。
entityが持つ属性を管理します。
そしてValue
▼values_table
id | entities_id | attributes_id | value |
---|---|---|---|
1 | 1 | 1 | sasakure |
2 | 1 | 2 | 1984/12/03 |
3 | 1 | 3 | tokyo shibuya |
4 | 2 | 1 | tarou |
5 | 2 | 2 | 2002/01/22 |
6 | 2 | 3 | kanagawa kawasaki |
Valueは「値」なので、EntityとAttributesの組み合わせに対して値を管理します。
テーブル数は増え、value_tableのレコード数も増えますね。
これがソートされてなかったりしたら、テーブルをパッと見ただけでは
どれがどのユーザーのデータなのかは分かりません。
とあるユーザーの情報を集めるのもSQLならJOINしたりと面倒。
ん、ではなぜEAVモデルを使うのか。
それは柔軟に属性を変えられるからです。
例えばユーザーテーブルに「email」を追加したい場合、従来ならSQLでALTER TABLE文を使います。
もし、既に沢山のユーザーがいる場合は、更新も一苦労です。
例えばですが、とあるユーザーだけ属性を増やしたい場合があったとしても、全ユーザーに属性を増やす事になりますね。
でもEAVモデルならattributes_tableに属性「email」を増やすだけで済みます。
必要なentity(ユーザー)にだけvalueを設定してあげればいいのです。
では、ユーザーテーブルだけでなく、商品テーブルもEAVモデルにしましょう。
それぞれでentities_tableなんかを作る事もできますが、下記のようにすれば
同じテーブルで管理出来るようになります。
▼entity_types_table
id | name |
---|---|
1 | customer |
2 | product |
entityの種類を管理するテーブルを新設
▼entities_table
id | entity_types_id |
---|---|
1 | 1 |
2 | 1 |
3 | 2 |
4 | 2 |
customerとproductどちらのentityか分かるようにします。
▼attributes_table
id | entity_types_id | attributes_name |
---|---|---|
1 | 1 | name |
2 | 1 | birthday |
3 | 1 | address |
4 | 2 | name |
5 | 2 | price |
6 | 2 | image |
attributeにも商品情報用の属性を追加すればOKです。
values_tableはそのままで構いません。
どうでしょう? こんなデータの管理方法もあるんですねー。
SQLを書くには面倒な構造ですが、O/RマッパやNoSQLの利用が進むにつれ
EAVモデルを採用するケースも多くなるんだと思いました。
HttpURLConnectionでハマったこと
Androidアプリの開発に携わるようになったので、ちょっとそちらでハマった話。
アプリからどこぞのAPIを叩く時など、httpやhttpsで通信を行います。
その時利用したのが
java.net.HttpURLConnection
これを使うのがスタンダードみたい。
それでメソッドにはGETやPOST、PUTやDELETEなどを
setRequestMethod(String)で指定するわけだけど、
POSTを使う場合には setDoOutput(true) をしないといけない。
ただしGETの時にtrueを指定しても動作するから、
どんなメソッドを使う時もとりあえずsetDoOutput(true)にしてた。
で、実際使っていたら、GETメソッドでコールするAPIを
なぜかPOSTでコールしちゃう端末が現れてしまった。
4.0系の端末だけがPOSTになる。。
明示的にGETを指定しているにも関わらず、POSTになっちゃう。。。
途方に暮れていたら、こんな記事が
http://webdiary.com/tag/setdooutput/
Android4.0から仕様が変わり、
setDoOutput(true)にすると、いくらsetRequestMethod(String)で指定しても
POSTになるらしい。
よく見るとandroid developersのサイトにも書いてあった。
http://developer.android.com/reference/java/net/HttpURLConnection.html
各バージョンでのテストは重要だな〜
ブロック暗号方式に挑戦。 Mcryptを使ってみた
McryptでCBCモードを使う機会があったのでメモ
use strict; use warnings; use Mcrypt qw(:ALGORITHMS :MODES); use Digest::MD5 qw(md5_hex); my $FILE_NAME = 'kkkkk.txt'; my $FILE = '/home/sasakure/' . $FILE_NAME; my $td = Mcrypt->new( algorithm => Mcrypt::RIJNDAEL_128, mode => Mcrypt::CBC, ); warn "key length " . $td->{KEY_SIZE} . "\n"; # 16 warn "iv length " . $td->{IV_SIZE} . "\n"; # 16 warn "block length " . $td->{BLOCK_SIZE} . "\n"; # 16 # cipherによってそれぞれのサイズは変わってくる(確認してないけどたぶん) my $key = md5_hex('mynameis'); # md5はとりあえず16バイトになるから使っているだけ my $iv = md5_hex('sasakure'); $td->init( pack('H*', $key), $iv); open(my $fh, '<', $FILE) || die $!; while ( read ( $fh, my $buf, 16 ) ) { # ブロックサイズに合わせて暗号化しないと警告が出る。 my $residue = length($buf) % 16; my $padding_num = 16 - $residue; if ($residue > 0) { # 最後16バイトに満たない場合にパディングする。 map { $buf .= $_ } pack('C*', map { 0x00 } (1..$padding_num)); } print $td->encrypt( $buf ); } close($fh); exit;
そもそもブロック暗号方式というものに初めて触れたので、それもメモ
ブロック暗号について
暗号化したいデータを一定の長さに区切って暗号化します。
いくつかモードがあるけれど、僕が理解したのは下記2つ
ECBモード
1つの鍵で暗号化を行います。なので、鍵さえ知っていれば全てのブロックを複合化出来る事になります。
ランダムアクセスが出来る事も特徴の1つです。
CBCモード
Cipher Block Chainingの略です。チェーンという単語から何かが繋がっている感じがイメージ出来るかと思います。
鍵はECBと同様に1つですが、それだけではなく、隣のブロックの暗号化した結果を鍵と一緒に暗号化の材料とします。
暗号化したブロックと鍵を合わせて、新しい鍵を作ります。
その新しい鍵を使って次のブロックを暗号化します。
そこで暗号化されたブロックと、鍵をまた合わせて、更に次のブロックを暗号化します。
逆に複合化する時は隣のブロックが必要になります。
という事はECBのようにランダムアクセスは出来ません。
その代わりにECBよりも推測されづらくなるわけです。
ちなみに一番最初のブロックはiv(イニシャライズ ベクター)という値を使います。
一番最初のブロックは「暗号化された隣のブロック」が無いのでその代わりですね。