k01ken’s b10g

He110 W0r1d!

Airを使ってGo言語のWebアプリケーションフレームワークのGinのホットリロードを有効にする

開発環境は、Windows 10 Pro(64bit) + go version go1.15.3 windows/amd64

Go言語のWebアプリケーションフレームワークを使う際に、Webサーバーを立ちあげて、ソースコードを書き換えるたびに、サーバーを一時停止して、再起動させるのが面倒だったので、ホットリロードする方法がないか探して、Airが良いということなので、使うことにしました。

Airをインストール

コマンドプロンプト上で、以下のコマンドを実行し、Airをインストール

go get -u github.com/cosmtrek/air

終了したら、

air -v

とコマンドを打つと、以下のように表示されたら、インストール成功です。
f:id:k01ken:20210730144617p:plain

Ginのプロジェクトを作成

次に、コマンドプロンプト上で、以下のコマンドを実行

cd c:\  && mkdir gin_sample && cd gin_sample && go mod init

以下のソースコードを、同じディレクトリにmain.goという名前で保存します

package main

import(
  "github.com/gin-gonic/gin"
)

func main(){
  r := gin.Default()
  r.GET("/helloworld", func(c *gin.Context) {
    c.JSON(200, gin.H{
      "message": "HelloWorld"
    })
  }
  r.Run(":5000") 
}

次に、Airを初期化するために、以下のコマンドを実行

air init

そうすると、同じディレクトリ内に、.air.tomlというファイルが作成されています。
このまま、airとコマンドを打ってしまうと、ディレクトリ内にあるすべてのファイルを監視対象としてしまうので、除外するファイル、例えば、node_modulesは、[build]の欄の、exclude_dirのリストの中に追加しておきます。
実行すると、main.goが同じディレクトリ内のtmpディレクトリ以下にmain.exeとして実行するようになります。
ファイルを更新するたびに、main.exeは新しく作られます。

Airの実行

以下のコマンドを入力して、Airを実行します。

air

そうすると、監視するファイルのあるディレクトリ名の一覧がリストされていきます。それが終了すると、main.goが読み込まれて、実行ファイルmain.exeが作成され、そのままサーバーが実行。running...と表示され、[Gin-debug]のルーティングリストのメッセージが表示されると、実行開始の合図です。試しに、Webブラウザ上から、localhost:5000/helloworldにアクセスすると、以下のように表示されます。
f:id:k01ken:20210730150408p:plain

今度は、今回の本丸であるmain.goの書き換えが可能かやってみます。main.goのmessageをHelloWorldからHelloAirに変更して保存します。そうすると、 running...[GIN-debug]が表示されましたので、また、Webブラウザ上から、localhost:5000/helloworldにアクセスすると、以下のように表示されます。
f:id:k01ken:20210730150657p:plain
見事、書き換えられました。

■参考リンク
【Golang/Go言語】Airでホットリロードをする方法
cosmtrek / air

curlコマンド一覧

開発環境は、Windows 10 Pro(64bit) + curl 7.55.1 (Windows) libcurl/7.55.1 WinSSL。

結果を指定のファイルにアウトプットする

デフォルトではコンソールに出力されるが、指定のファイルに出力させることも可能
[コマンド]

curl -o <FILENAME> <URL>
curl --output <FILENAME> <URL>

[具体例]
カレントディレクトリにoutput.htmlとして出力する

curl -o output.html https://yahoo.co.jp/
curl --output output.html https://yahoo.co.jp/

GETでWebページのボディを取得する

[コマンド]

curl <URL>

[具体例]

curl https://www.yahoo.co.jp/

HEADでWebページのステータス行とヘッダーフィールドを取得する

[コマンド]
下記のどちらでも可能。

curl --head <URL>
curl -I <URL>

[具体例]

curl --head https://www.yahoo.co.jp/
curl -I https://www.yahoo.co.jp/

POSTでデータを送信する

[コマンド]
下記のどちらでも可能。

curl -d <KEY>=<VALUE> <URL>
curl --data  <KEY>=<VALUE> <URL>

送信したいデータが複数ある場合は、,でつなぐ

curl --data <KEY>=<VALUE>,<KEY2>=<VALUE2> <URL>


[具体例]
仮に、サーバーをlocalhostのポート番号8000番の/postというURLに、POSTで投稿する仕組みを作った場合。

curl -d name=taro http://localhost:8000/post
curl --data name=taro http://localhost:8000/post
curl -d name=taro,age=10 http://localhost:8000/post
curl --data name=taro,age=10 http://localhost:8000/post

ヘルプを取得

[コマンド]
下記のどちらでも可能。

curl -h
curl --help

curlのバージョンを取得

[コマンド]
下記のどちらでも可能。

curl -V
curl --version


■参考リンク
Man Page

Twitterの『トピックをフォロー』を消す方法

f:id:k01ken:20210718185908p:plain

タイムラインを見ているときに、たまに表示される[トピックをフォロー]が邪魔なので、今回はそれを消す方法をメモ。

公式のヘルプを検索して、実践しても、相変わらず表示されるので、他を検索したところ、以下のリンクを参考にして何とか解決。
Twitterのホームにこの「トピックをフォロー」って出てくるのがす... - Yahoo!知恵袋

1.自分のホーム画面に戻り、右側のキラキラアイコンをクリック
f:id:k01ken:20210718185943p:plain

2.最新のツイート表示に切り替えるをクリック
f:id:k01ken:20210718190051p:plain

Goのreflectを使う

開発環境は、Windows 10 Pro(64bit) + go version go1.15.3 windows/amd64

package main

import (
  "fmt"
  "reflect"
)

func main() {
  // 値のタイプを知る
  fmt.Println(reflect.TypeOf("Koiken")) // string
  // 型の種別を比較する
  fmt.Println(reflect.TypeOf("Koiken").Kind() == reflect.String) // true

  // 値のセット
  var s string
  // 中身を変更するのでポインタを渡す
  v := reflect.ValueOf(&s).Elem()
  fmt.Println(v.CanSet()) // true
  v.SetString("Hello reflect")
  fmt.Println(s) // Hello reflect
}

■参考リンク
reflect
The Laws of Reflection
Go 言語 reflect チートシート

Ginでバリデーションを使ってみる

開発環境は、Windows 10 Pro(64bit) + go version go1.15.3 windows/amd64

Go言語のWebアプリケーションフレームワークであるGinのバリデーションについてのメモ。

以下、サンプルプログラムを引用します。

package main

import(
"net/http"
"time"
"reflect"

"github.com/gin-gonic/gin"
"github.com/gin-gonic/gin/binding"
"github.com/go-playground/validator/v10"
)

type Booking struct {
	CheckIn  time.Time `form:"check_in" binding:"required,bookabledate" time_format:"2006-01-02"`
	CheckOut time.Time `form:"check_out" binding:"required,gtfield=CheckIn,bookabledate" time_format:"2006-01-02"`
}

func bookableDate(
	v *validator.Validate, topStruct reflect.Value, currentStructOrField reflect.Value,
	field reflect.Value, fieldType reflect.Type, fieldKind reflect.Kind, param string,
) bool {
	if date, ok := field.Interface().(time.Time); ok {
		today := time.Now()
		if today.Year() > date.Year() || today.YearDay() > date.YearDay() {
			return false
		}
	}
	return true
}

func main(){
  r := gin.Default()

  if v, ok := binding.Validator.Engine().(*validator.Validate); ok {
    v.RegisterValidation("bookabledate", bookableDate)
  }

  r.GET("/bookable", getBookable)
  r.Run(":8085")
}

func getBookable(c *gin.Context) {
  var b Booking
  if err := c.ShouldBindWith(&b, binding.Query); err == nil {
    c.JSON(http.StatusOK, gin.H{"message": "Booking dates are valid!"})
  } else {
    c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
  }
}

■参考リンク
カスタムバリデーション

Go言語で正規表現を扱う

開発環境は、Windows 10 Pro(64bit) + go version go1.15.3 windows/amd64

使っている正規表現のパターンはここに書いてます。Google製の正規表現エンジンであるRE2を使用しています。

マッチするかどうかをtrue/falseで返す

package main

import (
  "fmt"
  "regexp"
)

func main(){
  r := regexp.MustCompile(`^[a-z]+-[a-z]+$`)
  // true
  fmt.Println(r.MatchString("hello-world"))
  // false
  fmt.Println(r.MatchString("helloworld"))
}

グループ化して抽出させる

package main

import (
  "fmt"
  "regexp"
)

func main(){
  str := "hello-world"
  r := regexp.MustCompile(`^([a-z]+)-([a-z]+)$`)
  str = r.ReplaceAllString(str, "($1),($2)")
  fmt.Println(str) // (hello),(world)
}

■参考リンク
高速かつ省メモリなGoogleの正規表現ライブラリ re2 についてのメモ
逆引きGolang (正規表現)

VBA(Excel)でファイル関連のメモ

開発環境は、Windows 10 Pro(64bit)。

ファイルが存在するかチェック

If Dir("ファイルのフルパス") <> "" Then
  Debug.Print("ファイルは存在します")
Else
  Debug.Print("ファイルは存在しません")
End If

ファイル一覧を取得する

Dim buf As String
'例えば、拡張子が.xlsxのファイルとして
buf = Dir("*.xlsx") 'この時点で1つ目のファイル名が取得できる
Do While buf <> ""
  Debug.Print(buf)
  buf = Dir() '次のファイル名を取得
Loop

bufが空になるまでループする。Dir()をするたびに、1ファイルずつ読みだされる。

ファイルを削除する

ワイルドカードで指定もできる

Kill 絶対パス付きのファイル名

ファイルをコピーする

FileCopy ファイル名付きの絶対パスのコピー元,ファイル名付きの絶対パスのコピー先