StoryEdit 開発日誌

ウェブアプリ StoryEditを作ってましたが延期。普通のブログ。

Erlang の上で動くElixir

Elixirという言語があるらしい。
http://elixir-lang.org/

Erlang VMで動く、Rubyライクな言語だということ。

Rubyは、唯一、”嫌い”な言語。これは、なぜかというと、いちいちendをかかねばならないからである。制御構造のterminationに}ではなく、endを選んだというセンスは、もはや感覚の違いなのだろうし、cpp使ってreplaceでもすればいいじゃない、といわれてしまえばそれまでなのだろうが、なぜかこの感覚は拭えない。

そんなことより、Elixirという言語がでてきていることがニュースである。

Javaの上でJRubuとかJythonとか、そういうのが次々とでてきたように、次はErlangが、正確にはErlang VMが戦場になるのかもしれない。

ところで、以下のリソースを読んで、近々ErlangからScalaに浮気しようと思う。

http://www.slideshare.net/jeffz/why-java-sucks-and-c-rocks-final?from_search=1

Erlang試す

Erlangを触ってみた。とりあえず難解。

http://www.erlang.org/course/course.html
から、まずはSequential programmingについて。

関数定義

まずはともあれ、関数を定義する。

add(X) 
 -> X + 1.

まず、ドットがややこしい。ブロックの終わりにはドットをいれる。関数が複数行になるときは、カンマで接続していく。

add_and_sub(X)
  -> Y = X + 1,
     Z = Y - 2.

型はまだ宣言しなくていい。型なしでも、ダイナミックでもなく、推論される。

パターンマッチング

erlangには、forとかwhileがない、らしい。そのかわり再帰でかく。では終了条件をどうかくか。
ここで威力を発揮するのが、パターンマッチング。その名の通り、パターン(特定の条件)がマッチしたら、そちらをつかう、という感じ。
以下、引数Xから0までを掛け合わせる、factorial関数を書く。

factorial(0)
 -> 1;
factorial(X)
 -> X * factorial(X-1).

うむ。なるほど。直感的である。factorial関数が、0をもらったら1を返して、それ以外は、x * facto(x-1)を返せってことですね。まるで、数学の定義のように直感的にかけちゃうのが、特徴。ifとか使うのは、やはり手続き的だもの。しかし、手続き的な制約で、factorial(0)は、factorial(x)よりも前に書かないと正しく動作しない。笑 
記述として、パターンマッチが続く場合は、セミコロンを使う模様。

変数

いい忘れたが、記述にいくつかの制約がある。

  • 変数は大文字から始めるべし
  • 関数名にハイフンは用いるべからず


とりあえず、こんなところ。次はGuardについて書く。

jarから、シンボルを見つける

あるjarに、どんなクラスが入っているか見つけたい時はないだろうか?

C言語であれば、soやdllに入っているシンボルを見つけるのと同じ機能がjavaにもほしい。

$ jar -tf servlet-api.jar
META-INF/
META-INF/MANIFEST.MF
javax/
javax/servlet/
javax/servlet/http/
javax/servlet/jsp/
javax/servlet/resources/
javax/servlet/Filter.class
javax/servlet/FilterChain.class
javax/servlet/FilterConfig.class
javax/servlet/GenericServlet.class
javax/servlet/LocalStrings.properties
javax/servlet/RequestDispatcher.class
javax/servlet/Servlet.class
javax/servlet/ServletConfig.class
javax/servlet/ServletContext.class
javax/servlet/ServletContextAttributeEvent.class
javax/servlet/ServletContextAttributeListener.class
javax/servlet/ServletContextEvent.class
javax/servlet/ServletContextListener.class
javax/servlet/ServletException.class
javax/servlet/ServletInputStream.class
javax/servlet/ServletOutputStream.class
javax/servlet/ServletRequest.class
javax/servlet/ServletRequestAttributeEvent.class
javax/servlet/ServletRequestAttributeListener.class
javax/servlet/ServletRequestEvent.class
...

classとシンボルが1-1対応してるから、jar -tfでみれるんですね。めでたし。

Apache tomcatを起動する

なぜこうもエントリが少ないのか不明だが、Apache Tomcat 6を起動するまでの流れメモ。

バイナリディストリビューションに含まれる、RUNNING.txtに起動手順が書いてあるが、これがサクっとウェブに上がってないのは、なぜだろうか。Javaはネットではラフに取り上げられないのか??


(以下、Running.txtのとおりです)

  1. Binary Distributionを取得。http://tomcat.apache.org/download-60.cgi
  2. 適当に展開。($TOMCAT=$(HOME)/Download/apache-tomcatとでもしよう)
  3. 環境変数を設定。($CATALINA_HOME=$TOMCAT)
  4. JREがあるか確認。環境変数も大丈夫か、確認。($JAVA_HOMEなど)
  5. bin/startup.sh、もしくは、bin/catalina.sh start で起動

よし!簡単!

というわけでやってみるも、失敗。

$ echo $CATALINA_HOME
/home/xxxxx/D/apache-tomcat-6.0.37
$ bash bin/startup.sh 
Cannot find bin/catalina.sh
The file is absent or does not have execute permission
This file is needed to run this program
$ bash bin/catalina.sh 
The BASEDIR environment variable is not defined correctly
This environment variable is needed to run this program

おいおい。なんだっていうんだ。とりあえずcatalina.shに実行権限を付与して再実行。

$ bash bin/catalina.sh
The BASEDIR environment variable is not defined correctly
This environment variable is needed to run this program

catalina.shをながめていき、エラーメッセージで、該当箇所を絞る。

if [ ! -x "$BASEDIR"/bin/setclasspath.sh ]; then
  if $os400; then
    # -x will Only work on the os400 if the files are:                                                                                                         
    # 1. owned by the user                                                                                                                                     
    # 2. owned by the PRIMARY group of the user                                                                                                                
    # this will not work if the user belongs in secondary groups                                                                                               
    eval
  else
    echo "The BASEDIR environment variable is not defined correctly"
    echo "This environment variable is needed to run this program"
    exit 1
  fi
fi

結局、上の箇所が失敗してた。$BASEDIRではなく、setclasspath.shの実行権限がないことが原因ですね。ううむ、、、残念なエラーメッセージ。

$ bash bin/startup.sh          
Using CATALINA_BASE:   /home/xxxx/D/apache-tomcat-6.0.37
Using CATALINA_HOME:   /home/xxxx/D/apache-tomcat-6.0.37
Using CATALINA_TMPDIR: /home/xxxx/D/apache-tomcat-6.0.37/temp
Using JRE_HOME:        /usr/local/jdk1.7.0_40
Using CLASSPATH:       /home/xxxx/apache-tomcat-6.0.37/bin/bootstrap.jar

というわけで起動したようです。localhost:8080から確認。無事起動。

邪バ

久々にはまった。workaroundはかけたが、意味がわかってないのでメモ。

以下のような、ファイルのパスをURLで受け付けるコードがあった。

private final static String DEFAULT_CONFIGURATION = "config.yaml";

private URL getConfigURL() throws ConfigurationException {
  String configUrl = System.getProperty("xxxx.config");
  if (configUrl == null) 
    configUrl = DEFAULT_CONFIGURATION;

  URL url;
  try {
    url = new URL(configUrl);
    url.openStream().close();
  } catch (...) { ... }
  return url;
}

IntelliJから実行すると、Exceptionがスローされてしまう。Debuggerからの実行だと、実行パスが異なるんだろうと思い、絶対パス指定を試みる。DEFAULT_CONFIGURATIONを絶対パスに書き換える。しかし、例外が投げられてしまう。

System.getProperty("user.dir")などで、実行パスを調べたり、いろいろ試してて、結局以下の方法に。

//private final static String DEFAULT_CONFIGURATION = "config.yaml";
private final static String DEFAULT_CONFIGURATION = "/home/hoge/xxxx/conf/config.yaml";

private URL getConfigURL() throws ConfigurationException {
  String configUrl = System.getProperty("xxxx.config");
  if (configUrl == null) 
    configUrl = DEFAULT_CONFIGURATION;

  URL url;
  try {
    File f = new File(configUrl);
    url = f.toURI().toURL();
    url.openStream().close();
  } catch (Exception e) { ... }
  return url;
}

くそダサいので、toStringを使って、文字列を確認。'file:/'が先頭につくだけのようだ。このため、最終的に以下のように落ち着く。

private final static String DEFAULT_CONFIGURATION = "file:/home/hoge/xxxx/conf/config.yaml";

private URL getConfigURL() throws ConfigurationException {
  String configUrl = System.getProperty("xxxx.config");
  if (configUrl == null) 
    configUrl = DEFAULT_CONFIGURATION;

  URL url;
  try {
    url = new URL(configUrl);
    url.openStream().close();
  } catch (Exception e) { ... }
  return url;
}

これでうまく動く。

納得がいかないのは、絶対パスだと'file:'が必要で、もともとの表現だと、'file:'がついてなくてもファイルが読まれている点。これはなんでなのか、ドキュメントを読んでみてもいまいちわからぬ。


new URL(String)は、new URL(URL, String)の第一引数がNULLの場合と同じ、とある。んで、new URL(URL, String)はこちら。
http://docs.oracle.com/javase/jp/6/api/java/net/URL.html#URL(java.net.URL, java.lang.String)

うーむ。。。文字列がスラッシュではじまると、コンテキストが無視される、、、???
RFCへの参照ばっかりだし、ほんとにわかりにくすぎて時間ばかりとられる昨今。。。

UIColor で 16進数を使う

なぜかObjective-Cにも手をだす。viewがaddできることに気づいてからは、InterfaceBuilderなどに頼らないため、サクサクと作業がすすむ。

ところで、UIColorは、16進数指定ができないという謎仕様らしい。Stack overflowにナイスなマクロがあったのでそのまま使う。 

#define UIColorFromRGB(rgbValue) [UIColor colorWithRed:((float)((rgbValue & 0xFF0000) >> 16))/255.0 green:((float)((rgbValue & 0xFF00) >> 8))/255.0 blue:((float)(rgbValue & 0xFF))/255.0 alpha:1.0]

UIColor *color = UIColorFromRGB(0xffffaa);

urllib? urllib2? いやいや、requests?

久々に簡単なスクリプトを書いていたが、httpアクセスできるPythonのライブラリを探してみた。
はじめにurllibがひっかかる。直訳調で、かつクオリティが高いため、少し読むのがめんどくさいでおなじみのIBM Developersのリソースだ。


urllibの関数名で再度ひっかけてみる。すると、urllib2というライブラリがあるらしい、ってことだった。なるほど、urllib2のほうが新しそうだ。同じ関数名もあるので、import文だけを変更して動かしてみた。

すると、なんと、動かない。urllib2はurllibの上位互換かと思ったが、そうではないのか。と思い、urllibとurllib2の違いを調べることに。

すると、urllibでもurllib2でもない、requestsというライブラリがあることを知る。(StackOverflowで、その類の話題が質問されていたため)。

Requests: http://docs.python-requests.org/en/latest/index.html

ミーハーな私は、迷わずRequestsを使うことに。以下、メモ。


$ pip install requests
$python 
Python 2.7.3 (default, Apr 10 2013, 06:20:15) 
[GCC 4.6.3] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> import requests;
>>> requests.get("http://www.google.com")
<Response [200]>
>>> res = requests.get("http://www.google.com")
>>> res.text  # show HTML

いやぁ、らくちん。

追記:

どうやら、urllib2は使いにくいからという理由で開発されたらしい。機能が限定されてる分、使い勝手はあがっているという、’スタイリッシュコーディング’向きのライブラリだ。

proxyの設定で、no-proxyを強制できなさそうなので、おとなしくurllib2を使うことに。