tokuhirom's blog

spring mvc の interceptor のパスマッチャのやつ

Spring mvc の interceptor ってやつ。hook みたいなやつ。以下のようなパスの設定ができる。 excludePathPatterns の設定だけだと動かないとかいう説もあって、注意が必要。

registry.addInterceptor(new ThemeInterceptor()).addPathPatterns("/**").excludePathPatterns("/admin/**");

http://docs.spring.io/spring/docs/4.2.4.RELEASE/spring-framework-reference/html/mvc.html#mvc-config-interceptors

ここのパターンは PathMatcher でマッチするのだが、AntPathMatcher が事実上唯一の実装。 https://docs.spring.io/spring/docs/current/javadoc-api/org/springframework/util/AntPathMatcher.html このマッチャで利用可能なメタキャラクタは以下のもののみ。

? matches one character
* matches zero or more characters
** matches zero or more directories in a path

インターセプターで、特定のパスのみ認証スキップとかやってる場合、気をつけないとエラー表示ページとかがそのまま interceptor かかってて謎のリダイレクトかかったりしてだるいです。

以上。

Created: 2016-02-06 01:05:08 +0000
Updated: 2016-02-06 01:05:08 +0000

spring boot で、freemarker のテンプレートの読み込みがサーバー再起動しないと読まれなくてだるいって時の対処方法

spring boot はデフォルトでは classpath から読んでるので、まあなんか再読み込みさせるのが難しい。eclipse なら自動でコンパイルされるのでまだマシだが、intellij だとなんか遅いしイライラする。

そこで、build.gradleに以下のように記述し、template の読み込みパスを変更した。

bootRun {
    systemProperty "spring.freemarker.templateLoaderPath", "file:src/main/resources/templates/,classpath:/templates/"
}

freemarker が適当に file:// から直接読んでくれるので、ファイル変更したらすぐ読み込まれて便利。なぜ application.properties or application.yml に書かないのかというと、application.yml 的なものは common module に入れておいて、web module, admin module などがそれに依存するみたいな構成にしたいからで、そのような構成になっている場合、common module に sub project のパスを直ガキできないからです。

まあ、そんな感じ。

Created: 2015-12-19 01:14:59 +0000
Updated: 2015-12-19 01:14:59 +0000

xfce4で、スタートメニューを開くコマンド

xfce4-popup-whiskermenu

Created: 2015-12-19 01:14:59 +0000
Updated: 2015-12-19 01:14:59 +0000

AssertJ 用の IntelliJ postfix completion plugin を書いた

AssertJ の assertThat() をpostfix completion で入力したいと常々思っていて、誰か書いてくれないかなと思っていたけど誰も書いてくれないし、IntelliJ のプラグインというものを書いてみたかったので書いてみた。

https://github.com/tokuhirom/assertj-postfix-plugin

↑レポジトリはこちら。

IntelliJ のプラグインの情報は少なくて、どうもどこが本家なのかよくわからなかった。 http://www.jetbrains.org/intellij/sdk/docs/index.html たぶんこの辺。だと思う。

とりあえず検索してみたところ IntelliJ IDEAのPostfix補完プラグインを作るという記事が見つかったので、「こりゃあ、真似すれば簡単に実装できそうだなー」と思ったのが運の尽き。

どーも、ここに書いてある情報だけでは実装は無理っぽい。。 なんか実行時例外出るし。。そもそも俺 intellij plugin の書き方が全くわかってないし。。

で、いろいろ調べてみたところ、IntelliJ のプラグインは gradle つかって開発するのが楽っぽい。

gradle-intellij-plugin ってので、簡単にビルドできる。./gradlew runIdea ってすると、gradle が intellij idea のコミュニティエディションをダウンロードしてきてそれを実行してくれる。

https://github.com/JetBrains/gradle-intellij-plugin

build.gradle は以下の様な感じ。


plugins {
    id "org.jetbrains.intellij" version "0.0.32"
}

apply plugin: 'org.jetbrains.intellij'
apply plugin: 'java'


sourceCompatibility = 1.8

intellij {
    pluginName 'AssertJ Postfix Plugin'
}

group 'me.geso.assertj_postfix_plugin'
version '0.0.1'

task wrapper(type: Wrapper) {
    gradleVersion = '2.6'
}

repositories {
    mavenCentral()
}

ディレクトリ構成は以下のようになっている。

src
└── main
    ├── java
    │   └── me
    │       └── geso
    │           └── assertj_postfix_plugin
    │               ├── AssertJPostfixTemplateProvider.java
    │               └── AssertJTemplate.java
    └── resources
        ├── META-INF
        │   └── plugin.xml
        └── postfixTemplates
            └── AssertJTemplate
                ├── after.java.template
                ├── before.java.template
                └── description.html

src/main/resources/postfixTemplates/ 以下にテンプレートのデータが入っている。これは実際になにかの役に立つわけではないが、入れておかないと例外があがって死ぬ。各テンプレートごとに after.java.template, before.java.template, description.html の3つのファイルが必要だ。 これらのテンプレートは、以下のような場所に表示される。表示されるだけなので、動作には関係ない。

META-INF/plugin.xml がプラグインのメタデータ。プラグインのIDやらなんやらの基本的な設定がここに書いてある。

codeInsight.template.postfixTemplateProvider のあたりが重要で、テンプレートプロバイダを設定している。あとは他のプラグインでも一緒。

<idea-plugin version="2">
    <id>me.geso.assertj_postfix_plugin</id>
    <name>AssertJ Postfix Completion Plugin</name>
    <version>0.0.1</version>
    <vendor email="tokuhirom+intellij@gmail.com" url="http://64p.org">tokuhirom</vendor>

    <description><![CDATA[
        This plugin adds postfix completion template for assertj.
    ]]></description>

    <change-notes><![CDATA[
        <ul>
        <li>0.0.1 - The first release.
        </ul>
    ]]>
    </change-notes>

    <!-- please see http://www.jetbrains.org/intellij/sdk/docs/basics/getting_started/build_number_ranges.html for description -->
    <idea-version since-build="141.0"/>

    <extensions defaultExtensionNs="com.intellij">
        <codeInsight.template.postfixTemplateProvider language="JAVA"
                                                      implementationClass="me.geso.assertj_postfix_plugin.AssertJPostfixTemplateProvider"/>
    </extensions>

    <actions>
    </actions>

</idea-plugin>

で、テンプレートの入り口は以下のとおり。テンプレートのセットを作って返しているだけ。

package me.geso.assertj_postfix_plugin;

import java.util.HashSet;
import java.util.Set;

import org.jetbrains.annotations.NotNull;

import com.intellij.codeInsight.template.postfix.templates.JavaPostfixTemplateProvider;
import com.intellij.codeInsight.template.postfix.templates.PostfixTemplate;

public class AssertJPostfixTemplateProvider extends JavaPostfixTemplateProvider {
    private final HashSet<PostfixTemplate> templates;

    public AssertJPostfixTemplateProvider() {
        templates = new HashSet<>();
        templates.add(new AssertJTemplate());
    }

    @NotNull
    @Override
    public Set<PostfixTemplate> getTemplates() {
        return templates;
    }
}

テンプレートの実装、以下の様な感じになる。StringBasedPostfixTemplate ってやつを継承することにより、なんかそれっぽいテンプレートを書くだけでよいという感じになっている。

package me.geso.assertj_postfix_plugin;

import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;

import com.intellij.codeInsight.template.Template;
import com.intellij.codeInsight.template.Template.Property;
import com.intellij.codeInsight.template.TemplateManager;
import com.intellij.codeInsight.template.postfix.templates.StringBasedPostfixTemplate;
import com.intellij.codeInsight.template.postfix.util.JavaPostfixTemplatesUtils;
import com.intellij.psi.PsiElement;

public class AssertJTemplate extends StringBasedPostfixTemplate {

    public AssertJTemplate() {
        super("assertThat", "assertThat(expr);",
             JavaPostfixTemplatesUtils.selectorAllExpressionsWithCurrentOffset(JavaPostfixTemplatesUtils.IS_NON_VOID));
    }

    @Override
    public Template createTemplate(TemplateManager templateManager, String s) {
        Template template = super.createTemplate(templateManager, s);
        template.setValue(Property.USE_STATIC_IMPORT_IF_POSSIBLE, true);
        return template;
    }

    @Nullable
    @Override
    public String getTemplateString(@NotNull PsiElement psiElement) {
        return  "org.assertj.core.api.Assertions.assertThat($expr$);$END$";
    }
}

デバッガで実行すれば、プラグインが読み込まれた状態の IDEA が起動するので、動作を確認すればOK。普通の java アプリと同様に、デバッガでステップ実行とかもできる。便利。

出来上がったら、 https://plugins.jetbrains.com/ で publish すれば OK.

./gradlew publishPlugin やらでアップロードできるが、とりあえずは普通に ./gradlew buildPlugin して、form からアップロードした。plugin.xml が含まれてないと言われてアップロード失敗したので、./gradlew jar した jar をアップした。二回目からは publishPlugin でやれる。と思う。

そういうわけで、アップしてみてある。ご利用ください。と言いたいところだけど、まだ承認待なのでした。 https://plugins.jetbrains.com/plugin/8093?pr=

Created: 2015-12-19 01:14:59 +0000
Updated: 2015-12-19 01:14:59 +0000

C 言語で qsort_r がポータブルじゃなくて困る時の対策

https://github.com/noporpoise/sort_r

qsort は、ソート対象の変数以外を渡すことができないため、マルチスレッドのプログラムでは取り扱いづらい。tls 使えばいいが、それもなあ、という感じな時は、qsort_r を使いたい。

しかし qsort_r は標準化されていないため、ポータビリティが必要なケースでは使いづらい。

そこで sortr だ。sortr は、glibc 2.8 or later または BSD 環境下では qsortr を使い、linux 環境下では qsorts を利用し、何もなければ自前のソートルーチンでソートしてくれるという便利な奴である。

License も public domain なので使いやすくて良い。

Created: 2015-12-19 01:14:59 +0000
Updated: 2015-12-19 01:14:59 +0000

Perl5 での Plack に当たる Crust をみんなで作った話

この記事は Perl 6 Advent Calendar 2015 の1日目です。

Perl 6 は、2015年のクリスマスにリリースされることになっており、我々としてはそれを待ち受ける必要があると考えました。

Perl6 がリリースされた暁には、いろいろ遊ぼうかなという気持ちをみなさんお持ちだと思います。 Perl6 には夢が詰まっており、様々な機能が含まれている夢の言語です。

そういった、夢の機能については今後、クリスマスまでの間に、語られていきますが、本稿では、現実的な話をします。


今年のクリスマスに Perl6 がリリースされるぞ、という宣言がでたわけですが、そうなってくると、Perl6 をクリスマスから早速遊びたいなと思うわけですよね。

そして、私は web engineer なので、 Perl6 が出たら早速 web application を書きたいと思うわけです。

しかし、そこで気づいてしまう。Perl6 には Plack のようなものが無いと!

Perl6 に Plack のようなものがないし、当時まともな httpd の実装が存在していなかったのです! (実際には存在はしていたのですが、multi thread 対応していないし、なぜか当時の MoarVM は listen の backlog が 1 にハードコードされているためにまったく実用的ではなかったのです。この listen のバックログがハードコードされている問題は現在では修正されています)

これではいけない。と気づくわけです。まともな httpd が必要だ。 とりあえず fork(2) があれば、listen backlog が 1 にハードコードされているというハードな環境下でもなんとかなるだろうと思って、まず NativeCall ( Perl6 から FFI で C 関数をコールする機能) を使って fork を呼ぶようにしてみました。これはなかなかうまく動作したのですが、Mac で動作しないという問題が発見されました。

なぜか。

MoarVM は内部で libuv を利用しており、あらゆるソケット処理に libuv を利用しています。 libuv は fork をサポートしていません。より具体的に言うと mac の kqueue は fork をサポートしてないので、完全に詰みました。

対策として、ソケットライブラリを全部 NativeCall で実装することも考えたのですが(実装もしたのですが)、完全に本質を見失っている感じがしてきたので、この方針は諦めることにしました。


そうこうしているうちに、IO::Socket::Async ベースならわりと動くっぽいのではないかという話になり、IO::Socket::Async ベースで実装する方針に転換しました。

何度か書き直したのですが、まあそこそこ動くようになりました。

そのそこそこ動く実装が HTTP::Server::Tiny です。これは Perl5 の有名な httpd 実装である kazuhooku 氏による Starlet を参考に実装されており、HTTP/1.1 に対応した高速なサーバーです。 (Perl6 でできる範囲としてはかなり高速になるように実装しています。期待したパフォーマンスが出ていなければ、それは、、)

https://github.com/tokuhirom/p6-HTTP-Server-Tiny/


そういうわけで、HTTP::Server::Tiny ができたので、あとは Plack 相当のレイヤーを実装しようということになりました。

そこで、下記12名の Perl Monger が集まり、Plack を Perl6 に移植するプロジェクトに乗り出しました。

  • fayland
  • hiroraba
  • kentaro
  • lestrrat
  • mattn
  • moznion
  • retupmoca
  • softmoth
  • sugyan
  • syohex
  • syoichikaji
  • tokuhirom

https://github.com/tokuhirom/p6-Crust

結果として、2015年12月1日時点でほぼ Plack の機能を実装しております。 例えばイカのように実行すれば、さくっと httpd が立ち上がります。めっちゃ便利。

crustup -e 'sub { 200, [], ["OK"] }'

具体的にはイカのものが完備されています。

  • Crust::App::Directory
  • Crust::App::File
  • Crust::App::URLMap
  • Crust::Builder
  • Crust::Handler::FastCGI
  • Crust::Handler::HTTP::Easy
  • Crust::Handler::HTTP::Server::Tiny
  • Crust::Headers
  • Crust::Middleware::AccessLog
  • Crust::Middleware::Auth::Basic
  • Crust::Middleware::Conditional
  • Crust::Middleware::ContentLength
  • Crust::Middleware::ErrorDocument
  • Crust::Middleware::Lint
  • Crust::Middleware
  • Crust::Middleware::ReverseProxy
  • Crust::Middleware::Runtime
  • Crust::Middleware::StackTrace
  • Crust::Middleware::Static
  • Crust::Middleware::XFramework
  • Crust::MIME
  • Crust
  • Crust::Request
  • Crust::Request::Upload
  • Crust::Response
  • Crust::Runner
  • Crust::Test::MockHTTP
  • Crust::Test
  • HTTP::Message::PSGI


そんなわけで、ウェブアプリケーションをかく準備は整っています。

あとは Perl6 のリリースを待つだけや!!!!

明日は karupanerura さんの 無限リストであそぶ です。

http://qiita.com/advent-calendar/2015/perl6

Created: 2015-12-19 01:14:59 +0000
Updated: 2015-12-19 01:14:59 +0000

MoarVM における DESTROY メソッドの呼び出し手順

refcnt 型のインタープリタの場合デストラクタの呼び出しは極めて容易だが、GC の場合はちょっと面倒だ。

Rakudo の場合は、src/Perl6/Metamodel/Finalization.nqp にコードがある。

以下のように、DESTROY メソッドを持っているクラスを MoarVM に settypefinalize している。 ``` role Perl6::Metamodel::Finalization { has @!destroyers;

method setup_finalization($obj) {
    my @mro   := self.mro($obj);
    my int $i := nqp::elems(@mro);
    my @destroyers;
    while --$i >= 0 {
        my $class   := @mro[$i];
        my $destroy := $class.HOW.find_method($class, 'DESTROY', :no_fallback(1));
        if !nqp::isnull($destroy) && $destroy {
            nqp::push(@destroyers, $destroy);
        }
    }
    @!destroyers := @destroyers;
    if @destroyers {
        nqp::settypefinalize($obj, 1);
    }
}

method destroyers($obj) {
    @!destroyers
}

} ```

settypefinalize の処理は src/core/interp.c の以下の部分で処理される。

            OP(settypefinalize):
                MVM_gc_finalize_set(tc, GET_REG(cur_op, 0).o, GET_REG(cur_op, 2).i64);
                cur_op += 4;
                goto NEXT;

MVMgcfinalizeset により、クラスに MVMFINALIZETYPE フラグが付与される。 このフラグが付与されているとオブジェクトの新規作成を行う MVMgcallocateobject の中で、MVM_gc_finalize_add_to_queue(tc, obj); が呼ばれ、ファイナライズキューに詰められる。

というわけで、ファイナライズ処理が必要になっているものは別枠で処理される、ということでした。

Created: 2015-12-19 01:14:59 +0000
Updated: 2015-12-19 01:14:59 +0000

cmake で変数を全部ダンプする

cmake で現在利用可能な変数の名前とその値をすべてダンプしたいということがあると思う。そんな時にはこうしたらいい。

get_cmake_property(_variableNames VARIABLES)
foreach (_variableName ${_variableNames})
    message(STATUS "${_variableName}=${${_variableName}}")
endforeach()

http://stackoverflow.com/questions/9298278/cmake-print-out-all-accessible-variables-in-a-script

Created: 2015-12-19 01:14:59 +0000
Updated: 2015-12-19 01:14:59 +0000

valgrind でメモリリークの誤検出が起きる場合、suppression を指定する

valgrind は、問題がない場合でも誤検出することがママある。 そのような場合、suppressions ファイルを生成すればよい。

たとえば、dlopen() は内部でエラーメッセージ保存用のバッファを calloc で確保するが、このバッファは開放されないが、これはバグではないということになっている。See. https://sourceware.org/bugzilla/show_bug.cgi?id=14015

このような場合、以下のようにして、--gen-suppressions=all として、suppressions 設定をダンプさせることができる。

$ make -j 4 && valgrind --gen-suppressions=all --leak-check=full --show-leak-kinds=all ./a.out 
make: Nothing to be done for `all'.
==829== Memcheck, a memory error detector
==829== Copyright (C) 2002-2013, and GNU GPL'd, by Julian Seward et al.
==829== Using Valgrind-3.10.0 and LibVEX; rerun with -h for copyright info
==829== Command: ./a.out
==829==
==829==
==829== HEAP SUMMARY:
==829==     in use at exit: 32 bytes in 1 blocks
==829==   total heap usage: 437 allocs, 436 frees, 117,923 bytes allocated
==829==
==829== 32 bytes in 1 blocks are still reachable in loss record 1 of 1
==829==    at 0x4C2B974: calloc (in /usr/lib64/valgrind/vgpreload_memcheck-amd64-linux.so)
==829==    by 0x4E3668F: _dlerror_run (dlerror.c:141)
==829==    by 0x4E360C0: dlopen@@GLIBC_2.2.5 (dlopen.c:87)
==829==    by 0x407599: pone_compile_node (main.c:771)
==829==    by 0x407851: main (main.c:845)
==829==
{
    <insert_a_suppression_name_here>
    Memcheck:Leak
    match-leak-kinds: reachable
    fun:calloc
    fun:_dlerror_run
    fun:dlopen@@GLIBC_2.2.5
    fun:pone_compile_node
    fun:main
}
==829== LEAK SUMMARY:
==829==    definitely lost: 0 bytes in 0 blocks
==829==    indirectly lost: 0 bytes in 0 blocks
==829==      possibly lost: 0 bytes in 0 blocks
==829==    still reachable: 32 bytes in 1 blocks
==829==         suppressed: 0 bytes in 0 blocks
==829==
==829== For counts of detected and suppressed errors, rerun with: -v
==829== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 2 from 2)

この内容を t/myapp.supp などに保存する。そして、このファイルを指定して起動すると、以下のように、不要な警告をだまらせることができる。

$ make -j 4 && valgrind --suppressions=t/myapp.supp --leak-check=full --show-leak-kinds=all ./a.out
make: Nothing to be done for `all'.
==862== Memcheck, a memory error detector
==862== Copyright (C) 2002-2013, and GNU GPL'd, by Julian Seward et al.
==862== Using Valgrind-3.10.0 and LibVEX; rerun with -h for copyright info
==862== Command: ./a.out
==862==
==862==
==862== HEAP SUMMARY:
==862==     in use at exit: 32 bytes in 1 blocks
==862==   total heap usage: 437 allocs, 436 frees, 117,923 bytes allocated
==862==
==862== LEAK SUMMARY:
==862==    definitely lost: 0 bytes in 0 blocks
==862==    indirectly lost: 0 bytes in 0 blocks
==862==      possibly lost: 0 bytes in 0 blocks
==862==    still reachable: 0 bytes in 0 blocks
==862==         suppressed: 32 bytes in 1 blocks
==862==
==862== For counts of detected and suppressed errors, rerun with: -v
==862== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 2 from 2)
Created: 2015-12-19 01:14:59 +0000
Updated: 2015-12-19 01:14:59 +0000

C++ と valgrind

libstdc++ は内部でメモリプールを持っている上に、プロセス終了時に開放しないので、valgrind が勘違いする。

以下のような極めて単純なプログラムでも All heap blocks were freed にならない。

#include <iostream>
int main() {
    return 0;
}

この問題は以下のように公式の FAQ に掲載されている。

My program uses the C++ STL and string classes. Valgrind reports 'still reachable' memory leaks involving these classes at the exit of the program, but there should be none.
First of all: relax, it's probably not a bug, but a feature. Many implementations of the C++ standard libraries use their own memory pool allocators. Memory for quite a number of destructed objects is not immediately freed and given back to the OS, but kept in the pool(s) for later re-use. The fact that the pools are not freed at the exit of the program cause Valgrind to report this memory as still reachable. The behaviour not to free pools at the exit could be called a bug of the library though.

    Using GCC, you can force the STL to use malloc and to free memory as soon as possible by globally disabling memory caching. Beware! Doing so will probably slow down your program, sometimes drastically.

    With GCC 2.91, 2.95, 3.0 and 3.1, compile all source using the STL with -D__USE_MALLOC. Beware! This was removed from GCC starting with version 3.3.

    With GCC 3.2.2 and later, you should export the environment variable GLIBCPP_FORCE_NEW before running your program.

    With GCC 3.4 and later, that variable has changed name to GLIBCXX_FORCE_NEW.

There are other ways to disable memory pooling: using the malloc_alloc template with your objects (not portable, but should work for GCC) or even writing your own memory allocators. But all this goes beyond the scope of this FAQ. Start by reading http://gcc.gnu.org/onlinedocs/libstdc++/faq/index.html#4_4_leak if you absolutely want to do that. But beware: allocators belong to the more messy parts of the STL and people went to great lengths to make the STL portable across platforms. Chances are good that your solution will work on your platform, but not on others.

http://valgrind.org/docs/manual/faq.html#faq.reports

が、上記の方法は最近の gcc だとなぜかうまく動かすことができなかったので、諦めた。

valgrind --leak-check=yes --leak-resolution=high --show-reachable=yes ./a.out

として、qr/ERROR SUMMARY: 0 errors/ になることを確認してそれでよし、ということにした。

Created: 2015-12-19 01:14:59 +0000
Updated: 2015-12-19 01:14:59 +0000

jcmd が "well-known file is not secure" という IO 例外を上げてくるときの対処

jcmd が "well-known file is not secure" などと意味不明なことを申した場合、この例外は 以下の位置から上がっている。


JNIEXPORT void JNICALL Java_sun_tools_attach_LinuxVirtualMachine_checkPermissions
  (JNIEnv *env, jclass cls, jstring path)
{
    jboolean isCopy;
    const char* p = GetStringPlatformChars(env, path, &isCopy);
    if (p != NULL) {
        struct stat64 sb;
        uid_t uid, gid;
        int res;

        /*
         * Check that the path is owned by the effective uid/gid of this
         * process. Also check that group/other access is not allowed.
         */
        uid = geteuid();
        gid = getegid();

        res = stat64(p, &sb);
        if (res != 0) {
            /* save errno */
            res = errno;
        }

        /* release p here before we throw an I/O exception */
        if (isCopy) {
            JNU_ReleaseStringPlatformChars(env, path, p);
        }

        if (res == 0) {
            if ( (sb.st_uid != uid) || (sb.st_gid != gid) ||
                 ((sb.st_mode & (S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH)) != 0) ) {
                JNU_ThrowIOException(env, "well-known file is not secure");
            }
        } else {
            char* msg = strdup(strerror(res));
            JNU_ThrowIOException(env, msg);
            if (msg != NULL) {
                free(msg);
            }
        }
    }
}

この例外はちょっと不親切で、

  • attach しようとしているユーザーの uid がプロセスファイルの uid と違う
  • 同じくグループIDが違う
  • ファイルモードが IRGRP, IWGRP, IROTH, IWOTH のうちいずれかが立っている

ときに発生するのだが、実際に上がるケースとしては、sudo jcmd などとしてユーザーのプロセスにアタッチしようとしたなどの理由により発生することが多くて、sudo -uwww-data jcmd ... などとすればすむことが多い。

Created: 2015-12-19 01:14:59 +0000
Updated: 2015-12-19 01:14:59 +0000

Perl6 における イテレータの挙動のメモ

Perl6 のイテレータは、role Iterable を実装しているクラスから取得することができる。 Iterable には iterator メソッドが実装されていて、これを取り出せばよい。

my $iter = $obj.iterator();

この $iter は role Iterator でアレしてます。role Iterator には pull-one というメソッドがあります。pull-one はイテレータが最後に到達すると IterationEnd というシングルトンバリューを返すので、以下のように実装すれば生の iterator を直接さわって順番に舐めることができます。

use v6;
use nqp;

my $obj = [1,2,3];
my $iter = $obj.iterator;
while True {
    my $next = $iter.pull-one();
    if nqp::decont($next) =:= IterationEnd {
        last;
    }
    say $next;
}
say "done";

ただし、このようなローレベルな操作は普通必要ありません。

Created: 2015-12-19 01:14:59 +0000
Updated: 2015-12-19 01:14:59 +0000

Perl6 のフィボナッチ数列生成についての解説

mattn ブログで紹介されている Perl6 のフィボナッチ数列が奇妙に見える人が多いようなので、まともな解説。

ref. http://mattn.kaoriya.net/software/lang/perl6/20151026144119.htm

フィボナッチ数列とは以下のような数列です。

1, 1, 2, 3, 5, 8, 13, 21, 34, 55

最初の2つの数字が 1, 1 でして、その後のものは直前2つの数字を足したものです。

よって、Perl5 で記述した場合、先頭10個のフィボナッチ数列を求めるには以下のようになります。

use v5.16.0;

sub fib {
    state %memo; # 一応 memoize ぐらいはしておく

    my $n = shift;
    $memo{$n} //= do {
        if ($n == 0 || $n == 1) {
            1
        } else {
            fib($n-1) + fib($n-2);
        }
    };
}

sub fibs {
    my $n = shift;
    map { fib($_) } 0..$n;
}

say join(', ', fibs(10));

ですが、Perl6 では無限数列を扱う機能が充実しているため、こういったものは非常に単純に記述できます。

Perl6 での書き方を解説しましょう。

まず、先頭の数列を用意します。

1, 1

次に、続きは一つ前の項目と2つ前の項目の和であることを示します。

1, 1, -> $a, $b { $a + $b } ...*

ここで、-> $a, $b { $a + $b } はラムダ式です。これは ES6 などのものと同じですね。 ...* というのは、数列が続くことを示し、* は無限大を表します。こうすることで無限に続く数列を表すことができるのです。

Perl6 では、2項のラムダは * + * のように省略できるのでこれは

1, 1, *+* ...*

と表記することができます。

ここから、先頭10個を取り出すには

my @a = (1, 1, *+* ...*);
say @a[0..9];

また、レンジの右辺は ^10 のようにすれば「10は含まない」つまり「0~9」のレンジを作ることができるので、以下のように表記できます。

my @a = (1, 1, *+* ...*);
say @a[^10];

これをまとめると以下のようになります。

say (1, 1, *+* ...*)[^10];

ま、そんな感じです。

Created: 2015-12-19 01:14:59 +0000
Updated: 2015-12-19 01:14:59 +0000

Perl6 でリストから無限リストをつくる

問題

my @a = <yellow red green> のようなリストから 'yellow', 'red', 'green', 'yellow', 'red', 'green', ..* のような無限リストを作りたい。

答え

my @list1 = <a b c>; my @list = map {@list1[$_ % @list1.elems]}, (0..*); say @list[42..50] のようにすれば良い。

まとめ

perl6@irc.freenode.org で質問して答えを得たが、ちょっとむずかしすぎるなあという印象。

本当は <a b c> x * でやりたかった。

追記

my $list = (|<a b c> xx *); say $list[40..50]; で良いとのことになりました。

Created: 2015-12-19 01:14:59 +0000
Updated: 2015-12-19 01:14:59 +0000

WebSocket with Perl6

Yay, I released WebSocket.pm on ecosystem. You can write a WebSocket server very easy!

Here is an example chat server in Perl6. https://github.com/tokuhirom/p6-WebSocket/blob/master/eg/chat.pl6

use v6;

use HTTP::Server::Tiny;
use WebSocket::P6SGI;

sub MAIN(Int :$port=80) {
    my $html = $=finish;
    $html ~~ s:g/'<<<PORT>>>'/$port/;

    my $supply = Supply.new;

    my $s = HTTP::Server::Tiny.new(port => $port);
    $s.run(-> %env {
        say "request: %env<PATH_INFO>";
        given %env<PATH_INFO> {
            when '/' {
                200, [], [$html]
            }
            when '/echo2' {
                my $s;

                ws-psgi(%env,
                    on-ready => -> $ws {
                        $s = $supply.tap(-> $got {
                            $ws.send-text("GOT: $got");
                        });
                        say 'ready';
                    },
                    on-text => -> $ws, $txt {
                        $supply.emit($txt);

                        say 'sent.';
                        if $txt eq 'quit' {
                            say 'close it!';
                            $ws.send-close();
                        }
                    },
                    on-binary => -> $ws, $binary {
                        $ws.send-binary($binary);
                    },
                    on-close => -> $ws {
                        say "closing socket";
                        $s.close if $s;
                    },
                );
            }
            default {
                404, [], ['not found']
            }
        }
    });
}

=finish
<!doctype html>
<html>
<head>
    <meta charset="utf-8">
    <title>WS</title>
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <script type="text/javascript" src="https://code.jquery.com/jquery-2.1.4.min.js"></script>
    <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.5/css/bootstrap.min.css">
</head>
<body>
    <div class="container">
        <header><h1>WS</h1></header>
        <section class="row">
            <form id="form">
                <input type="text" name="message" id="message">
                <input type="submit">
            </form>
            <pre id="log"></pre>
        </section>
        <footer>Powered by <a href="http://perl6.org/">Perl6</a></footer>
    </div>
    <script type="text/javascript">
        function log(msg) {
            $('#log').text($('#log').text() + msg + "\n");
        }

        $(function () {
            var ws = new WebSocket('ws://localhost:<<<PORT>>>/echo2');
            ws.onopen = function () {
                log('connected');
            };
            ws.onclose = function (ev) {
                log('closed');
            };
            ws.onmessage = function (ev) {
                log('received: ' + ev.data);
                $('#message').val('');
            };
            ws.onerror = function (ev) {
                console.log(ev);
                log('error: ' + ev.data);
            };
            $('#form').submit(function () {
                ws.send($('#message').val());
                return false;
            });
        });
    </script>
</body>
</html>
Created: 2015-12-19 01:14:59 +0000
Updated: 2015-12-19 01:14:59 +0000

«を入力する方法»

Perl6 ではよく $<pairs>».made などと入力するシーンがあるが、これの入力方法はわかりづらい。 この記号は Guillemet と呼ばれていて、まあ ASCII の範囲外なので普通のプログラミング言語ではオペレータとして採用されていない。

タイピングの方法は以下が詳しい。

https://en.wikipedia.org/wiki/Guillemet#Typing_.22.C2.AB.22_and_.22.C2.BB.22_on_computers

Mac で ASCII キーボードなら Opt+Shift+\ で入力できる。日本語キーボードなら Alt+Shift+} なようだ。

Created: 2015-12-19 01:14:59 +0000
Updated: 2015-12-19 01:14:59 +0000

Shipped full featured Plack clone for Perl6 named `Crust`

Hi, i'm tokuhirom, one of the core developer of Plack.

During the past few weeks, I've been hack the Perl6. This is to celebrate the Christmas in the best mood.

I'm a minimalist, and I love a software built on clean and well tested parts. I mean tokuhirom loves CPAN. To write the practical web applications in Perl6, it has released some of the library.

  • HTTP::Server::Tiny - IO::Socket::Async based full-featured HTTP/1.1 PSGI ready web application server(Port of Starlet).
  • HTTP::Parser - Port of HTTP::Parser::XS(In pure Perl6, only ported HTTP request parser, for now).
  • Getopt::Tiny - Port of Getopt::Long
  • HTTP::MultiPartParser - multipart/form-data parser.

Finally, by using these software, we have succeeded in transplanting the Plack. It's named Crust.

https://github.com/tokuhirom/p6-Crust/

I, and documentation issue(you know, my English is not good)t contains following modules.

  • Crust::App::File
  • Crust::Handler::HTTP::Easy
  • Crust::Handler::HTTP::Server::Tiny
  • Crust::Headers
  • Crust::MIME
  • Crust::Middleware::AccessLog
  • Crust::Request
  • Crust::Request::Upload
  • Crust::Response

You can install it by panda.

panda install Crust.

And there is a crustup command. You can run your P6SGI application by following comamnd:

crustup -e '-> $env { 200, [], ["ok"] }'
crustup app.psgi

We need your contribution for this project. There are some missing parts.

Thanks,

Created: 2015-12-19 01:14:59 +0000
Updated: 2015-12-19 01:14:59 +0000

Getopt::Tiny for Perl6

Hi, I shipped Getopt::Tiny for Perl6's ecosystem.

https://github.com/tokuhirom/p6-Getopt-Tiny/

You can install it by panda command:

panda install Getopt::Tiny

And then, you can use it!

get-options($args, <
    e=s
    I=s@
    p=i
    h|host=s
>);

wow! it's really readable. enjoy it~~

Created: 2015-12-19 01:14:59 +0000
Updated: 2015-12-19 01:14:59 +0000

Raw::Socket was retired.

https://github.com/tokuhirom/p6-Raw-Socket/

I removed raw-socket from ecosystem. Because I had misunderstood the behavior of IO::Socket::Async.

IO::Socket::Async's behaviour is good enough to me. tap-ed callback function have each threads. these works concurrently

Created: 2015-12-19 01:14:59 +0000
Updated: 2015-12-19 01:14:59 +0000

Ported Cookie::Baker to Perl6

I ported @kazeburo san's great Cookie::Baker to Perl6.

https://github.com/perl6/ecosystem/pull/60

This is my third module for Perl6 ecosystem

Created: 2015-12-19 01:14:59 +0000
Updated: 2015-12-19 01:14:59 +0000

[mac][osx][java][mysql] JDBC で mysql につなごうとしたら "Communications link failure" のエラーが出るとき

gradle でテストを動かしていたら、途中で JDBC が "Communications link failure" と言って死ぬ場合がある。 これは com.mysql.jdbc.exceptions.jdbc4.CommunicationsException のメッセージだが、このメッセージ自体は、socket を connect することにしたということを示すのみで、それ以上の情報が無い。ただこのエラー自体は、OS レベルでエラー返して発生することがほとんどなので、strace -f とかして調べればよいですね。

ありがちなのは bind-address を 127.0.0.1 に設定しているのに他のサーバーからアクセスしたとからしい。


一方で、テストの実行途中でこのエラーが出る場合は、リソースが枯渇している可能性がある。 つまり、テストケースの中でリソースがリークしている可能性だ。

そういった場合、以下のようなスクリプトをささっと書いて使うのがよい。

これで、特定の名前のプロセスの開いているファイル数を調べて、しきい値よりも多くなったらその値を出す。

perl hoge.pl --limit=2000 java

とかで実行すればいい。

mac の場合、デフォルトだとプロセスあたりに開くことができるファイルの数が少なめに設定されているので、mac でだけ死ぬ場合はこれを疑うといい。


mysql connector/j の出すエラーが不親切なので mysql が悪いのかなとおもってログを見てみたりする場合もあるが、そもそも他の部分でファイルディスクリプタ開きすぎている場合などあるので、mysql だけを疑っていてもダメ(もちろん mysql まわりに問題がある場合もある)。

Created: 2015-09-28 08:28:46 +0000
Updated: 2015-09-28 08:28:46 +0000
Next page