上京エンジニアの葛藤

都会に染まる日々

VS Code で Perl を書くときに関数ジャンプできるようにする方法

はろー。こんにちは。

みなさん五月病ですか?はい、僕は患ってます。

ところで、Perl 書く時のエディタは Vim 派ですか?
それとも Emacs 派ですか?まあだいたい二手に別れますよね。
そんな僕は Vim 派でしたが、最近は VS Code を使っています。
理由は・・・なんとなくです。

VS Code 自体はデフォルトの設定でもわりかし便利なんですが、どうせなら拡張して関数ジャンプとかできるようにしたいなと思ったので、その方法をここに残します。(めっちゃ簡単)

導入手順

  1. 拡張機能 Perl を入れよう
    marketplace.visualstudio.com
  2. ローカルに ctags を入れよう Mac の人は以下
    brew install ctags
    ※Command Line Tools を入れてない人はインストールできないので、以下のコマンドで入れましょう
    xcode-select --install
  3. VS Code 再起動をして完了

簡単ですね。これで対象の関数にカーソルを当てて F12 で関数ジャンプ!!!
※導入の際はくれぐれも自己責任でお願いします!

react.js で keydown イベントで DOM を更新する方法

はろー。こんにちは。

react.js を最近ちょこちょこ触り始めたので、忘れんうちに書きます!

前提としてそもそもライフサイクルとか正しく理解していないし、redux ってなに???っていう状況なのですが、力技でごりごり前に進んでいきます。
書いてるうちに理解深まるやろ!!!って信じてます。

やりたいこと

「特定のキーを押下したタイミングでイベントを発火させて DOM を更新したい」

button タグを onClick で DOM を変更させるなどは、サンプルがたくさん転がっておりなんとなくでできました。
しかし単純に「→」を押下して DOM を変更させるのはどのライフサイクルで実行すればいいか悩みました。

悩んだ末の実装が以下です。

var React            = require('react');
var ReactDOM         = require('react-dom');
var createReactClass = require('create-react-class');

class SlideComponent extends React.Component {
  constructor(props, context, updater) {
    super(props, context, updater);
    this.state = { word : 'hoge' };
  }

  handleKeyDown(e) {
    if (e.keyCode == 39) {
      this.setState({word: 'foo'});
    }
  }

  componentDidMount() {
    window.addEventListener('keydown', this.handleKeyDown.bind(this));
  }

  render() {
    return (
      <h1>{this.state.word}</h1>
    )
  }
}

ReactDOM.render(
  React.createElement(SlideComponent),
  document.getElementById('content')
);

ポイントは window のリサイズなどのイベントを扱いたい場合は componentDidMount() でイベントを登録して使うそうで、今回は keydown のイベントを登録しそれがトリガーで発火させるようにしました。
とても簡単ですね。

おまけ

かの有名なコナミコマンドでイベントを発火させ DOM を更新する
コナミコマンド「↑↑↓↓←→←→BA」

var React            = require('react');
var ReactDOM         = require('react-dom');
var createReactClass = require('create-react-class');

var konamiCommand = [38, 38, 40, 40, 37, 39, 37, 39, 66, 65];
var input = [];  

class SlideComponent extends React.Component {
  constructor(props, context, updater) {
    super(props, context, updater);
    this.state = { word : 'hoge' };
  }

  handleKeyDown(e) {
    input.push(e.keyCode);
    if (input.toString().indexOf(konamiCommand) >= 0) {
      this.setState({word: 'KONAMI success!!!'});
      input = [];
    }
  }

  componentDidMount() {
    window.addEventListener('keydown', this.handleKeyDown.bind(this));
  }

  render() {
    return (
      <h1>{this.state.word}</h1>
    )
  }
}

ReactDOM.render(
  React.createElement(SlideComponent),
  document.getElementById('content')
);

Perl でバブルソートをしてみる

はろー。こんにちは。

今更ながらソートアルゴリズムを改めて復習しているので、バブルソートPerl でしてみたいと思います。

バブルソートとは

ソートのアルゴリズムの一つ。隣り合う要素の大小を比較しながら整列させること。最悪計算時間がO(n2)と遅いが、アルゴリズムが単純で実装が容易なため、また並列処理との親和性が高いことから、しばしば用いられる。安定な内部ソート。基本交換法、隣接交換法ともいう。(単に交換法と言う場合もある)
Wikipedia : https://ja.wikipedia.org/wiki/%E3%83%90%E3%83%96%E3%83%AB%E3%82%BD%E3%83%BC%E3%83%88

上記のように Wikipedia では解説されているのでわからない人は読んでください。

実際のコード

#!/usr/bin/perl
use warnings;
use strict;
use Data::Dumper;

my $array = [13, 5, 41, 20, 1];

for (my $i = 0; $i < scalar @$array - 1; $i++) {
    for (my $n = 1; $n < scalar @$array; $n++) {
        if (@$array[$n] < @$array[$n-1]) {
            my $tmp       = @$array[$n-1];
            @$array[$n-1] = @$array[$n];
            @$array[$n]   = $tmp;
        }
    }
}

warn Dumper $array;

1;

しんぷるにできました。

Perl スクリプトで usage を書いてみた

はろー。こんにちは。
最近暖かくなったり寒くなったりよくわからん毎日ですね
しかし体調を崩すことは全くありません。丈夫なもんです

ところで今回は簡単なスクリプトPerl で書いて、コマンドラインから扱いやすいように usage を出力されるようにしてみました

$ grep --help
usage: grep [-abcDEFGHhIiJLlmnOoqRSsUVvwxZ] [-A num] [-B num] [-C[num]]
    [-e pattern] [-f file] [--binary-files=value] [--color=when]
    [--context[=num]] [--directories=action] [--label] [--line-buffered]
    [--null] [pattern] [file ...]

具体的にこんなやつです
Linux コマンドを使う時確認するやつですよね

そこで実装する実際のスクリプトは、Twitter で該当のツイートをリツイートしているユーザーの情報を標準出力するスクリプトを書きました
実装は以下です

実装

#!/usr/bin/perl
use strict;
use warnings;
use feature qw( say state );

use Net::Twitter;
use Getopt::Long qw(:config posix_default no_ignore_case gnu_compat);
use Data::Validator;
use Encode qw ( encode_utf8 );

my $tweet_id;
my $print_key;
my $help;
GetOptions('i=i' => \$tweet_id, 'p=s' => \$print_key, h => \$help);
if ($help) {
    die show_help();
}
validate( tweet_id => $tweet_id, print_key => $print_key );

my $account = {
    consumer_key        => '%CONSUMER_KEY%',
    consumer_secret     => '%CONSUMER_SECRET%',
    access_token        => '%ACCESS_TOKEN%',
    access_token_secret => '%ACCESS_TOKEN_SECRET%',
};

my $nt = Net::Twitter->new({
    traits   => [qw/API::RESTv1_1/],
    consumer_key        => $account->{consumer_key},
    consumer_secret     => $account->{consumer_secret},
    access_token        => $account->{access_token},
    access_token_secret => $account->{access_token_secret},
});

my $retweet_user_ids = $nt->retweeters_ids({
    id            => $tweet_id,
    stringify_ids => 'true',
});

my $user;
my $retweet_user_list = [];
map { 
    $user = $nt->show_user({ user_id => $_}); 
    push @$retweet_user_list, $user
} @{ $retweet_user_ids->{ids} };

map { say encode_utf8 $_->{$print_key} } @$retweet_user_list;

sub validate {
    eval {
        state $rule = Data::Validator->new(
            tweet_id  => { isa => 'Int' },
            print_key => { isa => 'Str' },
        );
        my $args = $rule->validate(@_);
    };
    if ($@) {
        die show_help();
        exit;
    }
}

sub show_help {
    my $help_doc = <<EOF;
    get retweet info script
    Usage:
        perl $0 [options]
    Options:
        -i : tweet_id (Int)
        -p : print_key (Str)
            ex )
                id, screen_name, location
                https://developer.twitter.com/en/docs/accounts-and-users/follow-search-get-users/api-reference/get-users-show            
        -h : help
    Author
        okkun_sh <okkun.sh\@gmail.com> (\@okkun_sh on Twitter)
EOF
    return $help_doc;
}

使用方法

$ perl get_retweet_info.pl -h

    get retweet info script

    Usage:
        perl get_retweet_info.pl [options]

    Options:
        -i : tweet_id (Int)

        -p : print_key (Str)
            ex )
                id, screen_name, location
                https://developer.twitter.com/en/docs/accounts-and-users/follow-search-get-users/api-reference/get-users-show

        -h : help


    Author
        okkun_sh <okkun.sh@gmail.com> (@okkun_sh on Twitter)


$perl get_retweet_info.pl -i 1111111111 -p screen_name

-h をすることで usage が出力されるようになります
これでoption -i でツイート id の指定、
-p でリツイートしているユーザーの情報の指定をすればよいということがわかりますね

コードのポイントは、この部分です
GetOptions でオプションの引数の指定をしており、引数に対してバリデーションをかけてエラー時は usage が出力されるようにハンドリングしています
また -h を指定時は usage が出力されるようにもしています

use Getopt::Long;
use Data::Validator;

my $tweet_id;
my $print_key;
my $help;
GetOptions('i=i' => \$tweet_id, 'p=s' => \$print_key, h => \$help);
if ($help) {
    die show_help();
}
validate( tweet_id => $tweet_id, print_key => $print_key );

sub validate {
    eval {
        state $rule = Data::Validator->new(
            tweet_id  => { isa => 'Int' },
            print_key => { isa => 'Str' },
        );
        my $args = $rule->validate(@_);
    };
    if ($@) {
        die show_help();
        exit;
    }
}

sub show_help {
    my $help_doc = <<EOF;
    get retweet info script
    Usage:
        perl $0 [options]
    Options:
        -i : tweet_id (Int)
        -p : print_key (Str)
            ex )
                id, screen_name, location
                https://developer.twitter.com/en/docs/accounts-and-users/follow-search-get-users/api-reference/get-users-show            
        -h : help
    Author
        okkun_sh <okkun.sh\@gmail.com> (\@okkun_sh on Twitter)
EOF
    return $help_doc;
}

スクリプト自体はさくっと作ったので動作は怪しいですが、usage の書き方自体は参考になると思います!
完成してから知りましたが、Twitter API ではリツイート情報の取得上限が最大100件らしく全てを取得しきれませんでした。。

もっとシンプルに書ける方法などあれば、コメントください!

Parallel::ForkManager を使って並列処理してみた

ひょんなことから、並列処理が必要とされる場面があったので Parallel::ForkManager とやらを使ってみた

このモジュールを選定した理由は、threads か Parallel::ForkManager で迷ったが、使っている perlbrew では threads が使えなかったため今回は、Parallel::ForkManager を使用しました

ちなみに threads とは、いい感じにマルチスレッドを扱えるクラスです

perldoc.jp

では、Parallel::ForkManager の使い方を書いていきます

導入

cpanm Parallel::ForkManager
いつも通り cpanmコマンドでモジュールを入れちゃいましょう

実装

サンプルコードを載せておきます

#!/usr/bin/perl
use strict;
use warnings;
use feature 'say';

use Parallel::ForkManager;

my $methods = [
    'hoge',
    'foo',
    'bar',
];

my $pm = new Parallel::ForkManager->new(3);
# 子プロセスの最大値を指定し、オブジェクトを生成する

for my $method (@$methods) {
    $pm->start and next;
    # forkする

    if ($method eq 'hoge') {
        &hoge;
    }
    elsif ($method eq 'bar') {
        &bar;
    }
    elsif ($method eq 'foo') {
        &foo;
    }
    $pm->finish;
    # 子プロセスを kill する
}

$pm->wait_all_children;
# 子プロセスの終了を待つ
say "finish";

sub hoge {
    sleep(3);
    say "hoge";
}

sub bar {
    say "bar";
}

sub foo {
    sleep(5);
    say "foo";
}

結果

期待される出力順は、bar → hoge → foo の順ですが・・・

$ perl test.pl
bar
hoge
foo
finish

期待通りの動作でした
こんな感じで簡単にプロセスを fork し並列処理をすることが可能です

metacpan.org

今回は基本的なことしかしていませんが、今後もっと触っていきたいですねー

新しい環境に perlbrew を入れる時によく入れ忘れてエラーになるのでメモ

sudo yum install patch

上京エンジニアの2017年振り返り

今日で仕事納めでした、おっくんです。

今年の振り返りをさらっと書きます。

気がつけば、上京をして約半年が経った。
東京生活はもう慣れてきて標準語も板についてきた気がする。

さて、エンジニアとしてに振り返りをします。

良かったこと

  1. 優秀な会社で優秀なエンジニアの方と働ける環境を得ることができた
  2. Perl を習得してきた

1つ目

今年の3月まで大阪で勤めていた受託会社を退職し、東京の自社サービス中心の会社に勤めることができたことで、社内には優秀なエンジニアの方も多く素晴らしい環境を得ることができてよかったと思った。
もともと技術力に自信があるわけではなかったが、実際業務に携わると自分の技術力に低さをものすごく感じて刺激的な毎日を送っている。
この環境を存分に利用して自分自身成長していきたいと思う。

またこれって受託開発会社あるあると思うんですけど、作っては納品をするというサイクルをひたすら繰り返しており、品質ももちろん重要だがいかに早く納品することに注力し開発していた。
だから運用に携わることが少なかったので、自社サービスは作って終わりではなく我が子のような感覚ですごくやりがいを感じている。

2つ目

今まで PHP のみで開発を行ったことしかなくて、初めて違う言語をメインに業務を行った。
PHPPerl の影響を受けたとはいえど、習得するのにすごく苦戦した。
そしてまだ苦戦している。。

改善すべき点

  • 技術的なことや自分の考えのアウトプットが不足してしまった
  • 自身が運営しているサービスを成長させることができなかった
  • ネイティブアプリへの理解度が著しく低い

1つ目

とにかく技術ブログや Twitter を初めてみたがアウトプットが少ないのでもっとしないとあかんなあって思う。
特に来年は規模問わず登壇して自分の考えを発信したりしようと思う。

2つ目

趣味でもある Web サービスの開発でいくつかサービスを公開しているが悲しいことにほとんどアクセスがない。もちろんアイデア自体にも問題があるのかもしれないが来年こそは使われるサービスにしたい。
今は月々500円程度の超低スペックの VPS で複数サービス運用していてもなんら問題が起きないのが非常に悲しい!

3つ目

業務ではネイティブアプリの運用をメインに行っているが、ネイティブアプリの理解度が低く開発を進める上で困ることが多い。
今は個人のサービスを全て Web 作っているが、ネイティブアプリを作るなどしてみてもいいかもしれへんなーって思う。
理想は、Web サービス利用者増える → ネイティブアプリ版を作るという流れがええかな。

総括

振り返ってみるとなかなか濃い一年でした。
エンジニアとしての環境はすごく整っているので、生かすも殺すも自分次第やなって感じです。

うん、やっぱり文章を書くのが苦手! 来年は更新頻度を上げます。

年末年始は、ひたすら Perl 書きます。

良いお年をー