ようへいの日々精進XP

よかろうもん

infrataster-plugin-ftp を作ってリリースしました

tl;dr

前回, rspec-ftp を少し触ってみました. rspec に乗っかることで, FTP ユーザーの振る舞いをテスト出来るようにしてみたつもりです.

inokara.hateblo.jp

せっかくなので, infrataster のプラグインも作ってみようということで, fukuoka.rb #110 でもくもくしてみました.

そして, インテグレーションテスト的なものを追加して gem 化してリリースしてみました.

infrataster-plugin-ftp | RubyGems.org | your community gem host

よろしければご利用頂きまして, フィードバック等を頂けると幸いですmm

詳細は

READMEリポジトリ内の spec ディレクトリ以下を参考にして頂くとして, テストコードは以下のように書くことを想定しています.

require 'spec_helper'

describe server(:ftp_server) do
  describe ftp('welcome') do
    it 'check accessible' do
      expect(result.chomp).to eq('230 Login successful.')
    end
  end

  describe ftp('pwd') do
    it 'check `chroot` enabled' do
      expect(result).to eq('/')
    end
  end

  describe ftp('mkdir test_dir') do
    it 'run `mkdir`' do
      expect(result).to include '/test_dir'
    end
  end

  describe ftp('ls') do
    it 'run ls' do
      expect(result).to include 'sample.txt'
    end
  end
end

spec_helper.rb には以下のように FTP サーバーへの接続情報を記述します.

Infrataster::Server.define(
  :ftp_server,
  '192.168.0.6',
  ftp: { user: 'ftpuser', pass: 'supersecret', passive: true },
)

FTP サーバーに対して送信する FTP コマンド (lspwd 等) の挙動をテストするような感じになります. これを実行すると...以下のような結果となります.

$ docker-compose exec rspec-ruby25 rspec

server 'ftp_server'
  ftp:
    check accessible
  ftp:
    check `chroot` enabled
  ftp:
    run `mkdir`
  ftp:
    run ls

Finished in 0.07892 seconds (files took 0.7531 seconds to load)
4 examples, 0 failures

想定するユースケース

自分は FTP サーバーにユーザーを追加した際に, 追加したユーザーがそもそもログイン出来るのか, ユーザーは chroot されているのかをテストしたい場合に利用したいと考えています. その他, 単純に FTP サーバーを構築した後の基本的な動作確認にも利用出来るのではと考えています.

2018 年に FTP を利用するシチュエーションがどれだけあるか判りませんが, FTP クライアントを使って目視で確認という若干アナログな作業を Rspec というフレームワークの上でコード化出来るという意味ではこのプラグインは多少なりとも有用なのではと考えています.

以上

現場からの報告でした!ε≡≡ヘ( ´Д`)ノ

2018 年 10 月 19 日 (金)

ジョギング

  • 山王公園往復
  • 懸垂 5 回, 調子良かった

日課

  • (腕立て x 50 + 腹筋 x 50) x 3

枝豆

  • 今年も兵庫に住んでいる直美おばさんから丹波の黒枝豆が届いた
  • 奥さんが頑張って全部茹でて冷凍保存
  • 茹でたてを食べたけど味が濃くてとても美味しかった

俺のツールズ

Jekyll と Amazon S3 + CloudFront 版に作り変えた.

俺のツールズ

静的サイトの公開は S3 + CloudFront + Route53 + ACM が最高なんではないかと思うくらい, あっという間に公開にこぎつけることが出来た. 一番時間が掛かったのは Jekyll のテーマ選定かな.

明日は

jawsug-kagoshima.doorkeeper.jp

に参加して LT をさせて頂く予定.

今日のトゥウィート

業務と趣味の狭間で作った CLI ツールがいい感じにフィットする作業を淡々と行っていた. 少しは業務に役立って嬉しかった.

2018 年 10 月 18 日 (木)

ジョギング

  • 探検を兼ねて近所をぐるっと 30 分くらい走ってみた
  • 懸垂 5 回
  • 朝の駅南界隈はとにかく人が多いということが判った

日課

  • おやすみ

JAWS-UG 福岡 もくもく会 #13

  • 最も参加者が多い会になったかなー
  • 土曜日の JAWS-UG 鹿児島勉強会で LT やる予定なのでその資料を作ったりした
  • 毎回だけどワイワイいろんな話したり作業したり...いい感じでもくもく出来ていると思う

アルゴリズムとプログラミング 「第 3 章 ループの仕組み」の予習とまとめ

これは

放送大学教養学部の「アルゴリズムとプログラミング」という授業で使われる「アルゴリズムとプログラミング」という教材書籍を自分なりにまとめたものです.

第 3 章では, C 言語のループ処理に関連して for 文や while 文の基本的な内容について触れられています. 課題で gdb を使って繰り返し処理をステップ実行してみました.

尚, 本まとめについては, 以下の Github リポジトリで管理しており, 加筆修正はリポジトリのみ行います.

github.com

1. for ループ

1.1 for 文の形式

for 文は, 初期化 (initialization), 条件文 (condition), 反復文 (counter 又は loop), 本文 (body statement) を記述する.

for ( 初期文; 条件文; 反復文 )
  本文;

以下, サンプル.

/* code: ex3-1.c */
#include <stdio.h>

int main()
{
  int i;
  for (i = 0; i < 10; i++)
    printf ("%d\n", i);

  return 0;
}
  • このプログラムは 0 から 0 までの数字を表示する
  • 初期文は i = 0i という変数の値に 0 が代入されて初期化される
  • 条件文では i < 10 という式があり, 変数 i が 10 より小さい値ならば, printf 関数によって標準出力に変数 i の値が表示される
  • 反復文では i++ という式があり, 変数に値が 1 が加算される
  • for 文で複数の命令を繰り返したい場合には波括弧 {} を利用したブロック文を用いる

上記のコードを実行してみる.

$ gcc ex3-1.c -o ex3-1
$ ./ex3-1
0
1
2
3
4
5
6
7
8
9

以下, % を利用したモジュロ演算のサンプル.

/* code: ex3-2.c */
#include <stdio.h>

int main()
{
  int i;
  for (i = 0; i < 10; i++) {
    printf ("%d", i);
    if (0 != (i % 2))
      printf (" :odd\n");
    else
      printf (" :even\n");
  }

  return 0;
}

上記のコードを実行してみる.

$ gcc ex3-2.c -o ex3-2
$ ./ex3-2

0 :even
1 :odd
2 :even
3 :odd
4 :even
5 :odd
6 :even
7 :odd
8 :even
9 :odd

1.2 for 文の入れ子型ループ

以下のコードは for 文の中にさらに別の for 文のループを含む例. このようなループは入れ子型ループ (nested loop) と呼ばれる.

/* code: ex3-3.c */
#include <stdio.h>

int main()
{
  int i, j;
  for (i = 1; i < 10; i++) {
    for (j = 1; j < 10; j++) {
      printf ("%02d ", i * j);
    }
    printf ("\n");
  }
  return 0;
}

上記のコードを実行してみる.

$ gcc ex3-3.c -o ex3-3
$ ./ex3-3
01 02 03 04 05 06 07 08 09
02 04 06 08 10 12 14 16 18
03 06 09 12 15 18 21 24 27
04 08 12 16 20 24 28 32 36
05 10 15 20 25 30 35 40 45
06 12 18 24 30 36 42 48 54
07 14 21 28 35 42 49 56 63
08 16 24 32 40 48 56 64 72
09 18 27 36 45 54 63 72 81

外側のループでは for 文により変数 i が 1 〜 9 まで増加する, 同様に内側のループでは for 文によって変数 j が 1 〜 9 まで増加する為, 上記の結果は九九表のような表示結果となる.

1.3 for 文の無限ループ

以下のコードは for 文を使った無限ループ (infinite loop) の例. 初期文, 条件文, 反復文に何も記述されていない (又は, 条件文が常に真となる条件) 為, 本文が無限に実行される.

/* code: ex3-4.c */
#include <stdio.h>

int main()
{
  int i;
   
  i = 0;
  for (;;) {
    printf ("%d ", i);
    i++;
  }
  return 0;
}

上記のコードを実行してみる. (今回からコンパイル環境は gcc version 6.3.0 20170516 (Debian 6.3.0-18+deb9u1) でやっていく.)

$ gcc ex3-4.c -o ex3-4 -g3
$ ./ex3-4
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17..... 一瞬で大変なことになる.

放っておいても, ループ内でメモリを消費するようなコードであれば, いずれエラーで停止する.

2. while 文

2.1 while 文の形式

while 文は以下のような形式となる.

while ( 条件文 )
  本文;

以下, コード例. 変数 i に初期値として 0 が代入される. while 文によって条件文 i < 10 が真の間は本文の printf 関数が実行され, 0 から 9 までの値が標準出力で表示される.

/* code: ex3-5.c */
#include <stdio.h>

int main()
{
  int i;

  i = 0;
  while (i < 10) {
    printf ("%d ", i++);
  }
  printf ("\n");
  return 0;
}

このコードをコンパイルして実行してみる.

$ gcc ex3-5.c -o ex3-5 -g3
$ ./ex3-5
0 1 2 3 4 5 6 7 8 9

C 言語の場合, 整数である変数 i の値は, 宣言した場所で自動的に 0 で初期化される為, i = 0; 自体は不要な処理に見えるが, 初期の Pascal 等のプラグラミング言語では 0 等での値での変数初期化保証していない場合もあるので, 変数を利用する前に初期化をすることが望ましいとされている.

コード ex3-5.c は以下のように書き換えることも出来る.

/* code: ex3-6.c */
#include <stdio.h>

int main()
{
  int i;

  i = 0;
  while (i < 10) {
    printf ("%d ", i);
    i++;
  }
  printf ("\n");
  return 0;
}

このコードをコンパイルして実行してみる.

$ gcc ex3-6.c -o ex3-6 -g3
$ ./ex3-6
0 1 2 3 4 5 6 7 8 9

2.2 do-while 文の形式

do-while 文の形式は以下の通り.

do
  本文;
while ( 条件文 );

while 文と異なるのは, 本文が先に実行され, その後に条件文が評価されることで, 本番が少なくとも 1 回は実行される必要があるプログラムを作成する時に便利.

以下, コード例.

/* code: ex3-7.c */
#include <stdio.h>

int main()
{
  int i;

  i = 0;
  do {
    printf ("%d ", i);
    i++;
  } while (i < 10);
  printf ("\n");
  
  return 0;
}

このコードをコンパイルして実行してみる.

$ gcc ex3-7.c -o ex3-7 -g3
$ ./ex3-7
0 1 2 3 4 5 6 7 8 9

2.3 while 文の入れ子ループ

for 文同様に while 文でも入れ子ループは書くことは出来る. 以下のコードは ex3-3.c を while 文で書き換えたもの.

/* code: ex3-8.c */
#include <stdio.h>

int main()
{
  int i, j;
  
  i = 1;
  while (i < 10) {
    j = 1;
    while (j < 10) {
      printf ("%02d ", i * j);
      j++;
    }
    printf ("\n");
    i++;
  }
  return 0;
}

このコードをコンパイルして実行してみる.

$ gcc ex3-8.c -o ex3-8 -g3
$ ./ex3-8
01 02 03 04 05 06 07 08 09
02 04 06 08 10 12 14 16 18
03 06 09 12 15 18 21 24 27
04 08 12 16 20 24 28 32 36
05 10 15 20 25 30 35 40 45
06 12 18 24 30 36 42 48 54
07 14 21 28 35 42 49 56 63
08 16 24 32 40 48 56 64 72
09 18 27 36 45 54 63 72 81

2.4 while 文の無限ループ

以下のコードは while 文による無限ループの例. 条件文が 1 である為, 常に真となり無限ループとなる.

/* code: ex3-9.c */
#include <stdio.h>

int main()
{
  int i;
   
  i = 0;
  while (1) {
    printf ("%d ", i);
    i++;
  }
  return 0;
}

このコードをコンパイルして実行してみる.

$ gcc ex3-9.c -o ex3-9 -g3
$ ./ex3-9
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17..... 一瞬で大変なことになる.

2.5 break 文と continue 文

break 文を利用すると, break 文を使用した場所でループを終了させることが出来る. 以下, コード例.

/* code: ex3-10.c */
#include <stdio.h>

int main()
{
  int i;
   
  i = 0;
  while (1) {
    printf ("%d ", i);
    if (i ==5) {
      i = 0;
      break;
    }
    i++;
  }
  printf ("\n");
  return 0;
}

このコードをコンパイルして実行してみる.

$ gcc ex3-10.c -o ex3-10 -g3
$ ./ex3-10
0 1 2 3 4 5

このコードでは while 文により無限ループとなり変数 i が増加していくが, 変数 i の値が 5 になったところで, 変数 i に 0 が代入され break 文が実行される. これによって, while 文から脱してプログラムが終了する.

continue 文は, continue 文が実行された場所でループ処理が中断し, ループの条件文が評価され, 条件文が真であればループ本文の先頭の命令から実行が行われる. 以下, コード例.

/* code: ex3-11.c */
#include <stdio.h>

int main()
{
  int i;
   
  i = 0;
  while (1) {
    printf ("%d ", i);
    if (i == 5) {
      i = 0;
      continue;
    }
    i++;
  }
  printf ("\n");
  return 0;
}

このコードをコンパイルして実行してみる.

$ gcc ex3-11.c -o ex3-11 -g3
$ ./ex3-11
0 1 2 3 4 5 0 1 2 3 4 5 0 1 2 3 4 5 0 1 2 3... 0 1 2 3 4 5 が繰り返される

このコードでは while 文により無限ループとなり変数 i が増加していくが, 変数 i の値が 5 になったところで, 変数 i に 0 が代入されて continue 文が実行される. ここでループ処理が中断してループの条件文が評価される. 条件文は 1 で常に真であることから, 再びループ本文の先頭から命令が実行される為, 0 1 2 3 4 5 が繰り返し表示される.

3. for 文と while 文の変換

以下, for 文と while 文の形式を比較したもの.

// for 文
for ( 初期文; 条件文; 反復文) {
  本文;
}

// while 文
初期文;
while ( 条件文 ) {
  本文;
  反復文;
}

上記ように, 初期文, 条件文, 反復文の配置を変えることにより for 文, while 文の相互変換が可能となる.

一般的には, ループの処理に入る前に本文の命令を何回繰り返すかが明らかになっているような場合には for 文を, ループの終了条件が本文の命令で決定され, ループの終了の条件が予期しにくい場合には while 文が使われることが多い.

演習問題

問 3.1

以下のコード (コード 3.1) を変更し, 0 から 99 までの数字を表示するようにしなさい.

/* code: ex3-1.c */
#include <stdio.h>

int main()
{
  int i;
  for (i = 0; i < 10; i++)
    printf ("%d ", i);

  return 0;
}

以下, 解答例.

/* code: q3-1.c */
#include <stdio.h>

int main()
{
  int i;
  for (i = 0; i < 100; i++) {
    printf ("%d ", i);
  }

  return 0;
}

コンパイルして実行してみる.

$ gcc q3-1.c -o q3-1 -g3
$ ./q3-1
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99

更にこれを while 文で書き換えてみる.

/* code: q3-1.c */
#include <stdio.h>

int main()
{
  int i;
  
  i = 0;
  while (i < 100) {
    printf ("%d ", i);
    i++;
  }

  return 0;
}

一応, これもコンパイルして実行してみる.

$ gcc q3-1.c -o q3-1 -g3
$ ./q3-1
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99

問 3.2

問 3.1 の q3-1.c を変更して 0 から 9 までの数字を降順に表示するようにしなさい.

以下, 解答例.

/* code: q3-2.c */
#include <stdio.h>

int main()
{
  int i;
  for (i = 9; i >= 0; i--) {
    printf ("%d ", i);
  }

  return 0;
}

これをコンパイルして実行してみる.

$ gcc q3-2.c -o q3-2 -g3
$ ./q3-2
9 8 7 6 5 4 3 2 1 0

先程と同様に while 文でも書いてみる.

/* code: q3-2.c */
#include <stdio.h>

int main()
{
  int i;
  i = 9;
  while (i >= 0) {
    printf ("%d ", i);
    i--;
  }

  return 0;
}

一応, コンパイルして実行してみる.

$ gcc q3-2.c -o q3-2 -g3
$ ./q3-2
9 8 7 6 5 4 3 2 1 0

問 3.3

問 3.1 の q3-1.c を for 文を使ったコードから while 文を使ったコードに変更しなさい.

以下, 解答例.

/* code: q3-3.c */
#include <stdio.h>

int main()
{
  int i;
  
  i = 0;
  while (i < 100) {
    printf ("%d ", i);
    i++;
  }

  return 0;
}

問 3.4

以下のコードの実行した時の出力内容を答えなさい.

/* code: q3-4.c */
#include <stdio.h>

int main()
{
  int i, j, k;
  
  for (i = 0; i < 2; i++) {
    for (j = 0; j < 2; j++) {
      for (k = 0; k < 2; k++) {
        printf ("%d %d %d", i, j, k);
        printf ("\n");
      }
    }
  }
  return 0;
}

普通にコンパイルして実行してみる.

$ gcc q3-4.c -o q3-4 -g3
$ ./q3-4
0 0 0
0 0 1
0 1 0
0 1 1
1 0 0
1 0 1
1 1 0
1 1 1

普通にコンパイルして実行するのは少し学びが無いので gdb でステップ実行してみる.

$ gdb ./q3-4
...
Reading symbols from ./q3-4...done.
(gdb) b main
Breakpoint 1 at 0x708: file q3-4.c, line 8.
(gdb) run
Starting program: /work/q3-4

Breakpoint 1, main () at q3-4.c:8
8         for (i = 0; i < 2; i++) {
(gdb) n
9           for (j = 0; j < 2; j++) {
(gdb) n
10            for (k = 0; k < 2; k++) {
(gdb) n
11              printf ("%d %d %d", i, j, k);
(gdb) n
12              printf ("\n");
(gdb) n
0 0 0
10            for (k = 0; k < 2; k++) {
(gdb) n
11              printf ("%d %d %d", i, j, k);
(gdb) n
12              printf ("\n");
(gdb) n
0 0 1
10            for (k = 0; k < 2; k++) {
(gdb) n
9           for (j = 0; j < 2; j++) {
(gdb) n
10            for (k = 0; k < 2; k++) {
(gdb) n
11              printf ("%d %d %d", i, j, k);
(gdb) n
12              printf ("\n");
(gdb) n
0 1 0
10            for (k = 0; k < 2; k++) {
(gdb)
...

おお.

問 3.5

以下のコードの実行した時の出力内容を答えなさい.

/* code: q3-5.c */
#include <stdio.h>

int main()
{
  int i, j, k;
  
  for (i = 0; i < 2; i++) {
    for (j = 0; j < 2; j++) {
      for (k = 0; k < 2; k++) {
        printf ("%d ", i * j + k);
      }
    }
  }
  return 0;
}

普通にコンパイルして実行してみる.

$ gcc q3-5.c -o q3-5 -g3
$ ./q3-5
0 1 0 1 0 1 1 2

gdb でステップ実行してみる. (上記のコードに改行 ("\n") を追加している)

(gdb) b main
Breakpoint 1 at 0x708: file q3-5.c, line 8.
(gdb) run
Starting program: /work/q3-5

Breakpoint 1, main () at q3-5.c:8
8         for (i = 0; i < 2; i++) {
(gdb) n
9           for (j = 0; j < 2; j++) {
(gdb) n
10            for (k = 0; k < 2; k++) {
(gdb) n
11              printf ("%d ", i * j + k);
(gdb) n
12              printf ("\n");
(gdb) n
0
10            for (k = 0; k < 2; k++) {
(gdb) n
11              printf ("%d ", i * j + k);
(gdb) n
12              printf ("\n");
(gdb) n
1
10            for (k = 0; k < 2; k++) {
...

ふむふむ.

以上

  • for と while の相互変換, 雰囲気掴めた
  • gdb の使い方を勉強せねば...

2018 年 10 月 17 日 (水)

ジョギング

  • 山王公園往復
  • 懸垂 5 回
  • 公園に着くやいなや腹痛に襲われ, 公園のトイレに駆け込むもトイレットペーパーの配備が無くてかなり焦った (注意が必要)
  • 結局, 近くのローソンに駆け込み事なきを得た (今度, ここのローソンで買い物しよう)

日課

  • おやすみ

fukuoka.rb #110

  • 久しぶりの参加
  • グルーブノーツさんに来ている海外からのインターン生も一緒に参加ということで, 自己紹介英語で...

寒い感じになったが, やっぱり英語は必要だよなって. ジョークをサラッと英語で言えるようになりたい.

で, もくもくの成果としては, 以前に rspec-ftp を弄らせてもらったので, その勢いで infrataster のプラグインを作ってみた.

rspec-ftp とはちょっとアプローチが違うけど, FTP のコマンド操作とその結果をテスト出来するアプローチで, こちらの方が汎用性高そうな気がするので, テストを書いたりしてちゃんと育てていこうと思う.

2018 年 10 月 16 日 (火)

ジョギング

  • 山王公園往復
  • 右足, やっぱり変な感じがある
  • 懸垂 3 回 + 2 回

日課

  • (腕立て x 50 + 腹筋 x 50) x 3

パスタ

  • 久しぶりに作った
  • トマトピューレを使ってみたけど仕上がりがパサパサで残念な感じになった

2018 年 10 月 15 日 (月)

ジョギング

  • 山王公園往復
  • 右足, やっぱり変な感じがある
  • 懸垂 5 回

日課

  • (腕立て x 50 + 腹筋 x 50) x 3

マッサージ

  • お昼休みを利用して近所のマッサージ屋さんへ
  • 右腰から右足をちゃんと施術してもらいたかったけど, 思ったほど解れていない感じ...残念.

今日のトゥウィート

YANGMAN ではなくて, YOUNGMAN だったのに...ツイートして少し経ってから気づいた...orz

2018 年 10 月 14 日 (日)

ジョギング

  • 山王公園往復
  • 右腰, 右足, やっぱり変な感じがある
  • 懸垂 3 + 2 + 2 回, 連続で 5 回が出来るようになりたい

日課

  • お休み

モスバーガー

  • 久しぶりにモスバーガーを食べた
  • ポテイトのセットでめっちゃ美味しかったし, ハンバーガーの食べ方も上手くなったはず

ダイニングチェアが届いた

シャレオツ(?)なダイニングチェアを導入した。

シャレオツな感じで気に入っている.

2018 年 10 月 13 日 (土)

ジョギング

  • おやすみ

日課

  • おやすみ

ミニツーリング

ミニディーラー企画のツーリング大会に参加した. 目的地は阿蘇. 初めてツーリングに参加してみたけど, 駐車場に同じような車がズラーッと並ぶ様は圧巻で興奮した.

ミニだらけ。#mini #minicooper #ミニだらけ

ツーリング大会は現地解散で, その後, そのままミニで大観峰まで登った.

大観峰で大感動。#mini #ミニで見に来た

天気も良くて空も澄んでいたので大感動しかなかった.

2018 年 10 月 12 日 (金)

ジョギング

  • 山王公園往復
  • 右足, やっぱり変な感じがある
  • 懸垂 5 回

日課

  • (腕立て x 50 + 腹筋 x 50) x 3

夕飯は麻婆鍋を作った

丸美屋の麻婆豆腐の素を使った鍋. そこそこ美味しかったけど, パンチのある辛さと旨味がイマイチだった.

今日のトゥウィート

JAWS-UG 福岡もくもく会, 13 回目を迎えた. 100 回目はいつになるだろう.