2021年9月22日水曜日

Python でコードから UML (クラス図) を生成する方法

Python でコードから UML (クラス図) を生成する方法

概要

pyreverse コマンドは pylint モジュールに取り込まれているのでそちらを使うのがポイントです

環境

  • macOS 11.5.2
  • Python 3.8.3
  • pyreverse in pylint 2.10.2

インストール

pylint とインストールすると pyreverse もインストールされます

  • pipenv install pylint

テストコード

class User:

    def __init__(self, name, age):
       self.name = name
       self.age = age

    def show(self):
        print("{} => {}".format(self.name, self.age))

class SuperUser(User):

    def __init__(self, name, age):
        super().__init__(name, age)
        self.admin = True

    def show(self):
        super().show()
        print(self.admin)


u1 = User("hawk", 10)
u1.show()
admin = SuperUser("snowlog", 20)
admin.show()

動作確認

  • pipenv run pyreverse -o png test.py
  • open classes.png

最後に

pyreverse 単体ではほぼメンテされてませんが pylint 側に取り込まれているようなので pylint を使える環境であればそちらの pyreverse を使いましょう

2021年9月21日火曜日

Ruby で UML を出力する

Ruby で UML を出力する

概要

Ruby のコードから UML を出力するのに xumlidot というツールを使ってみました
使い方と出力結果を紹介します

注意点として Ruby3 系には対応していません https://github.com/os6sense/xumlidot/issues/36

環境

  • macOS 11.5.2
  • Ruby 2.6.6 3.0.2p107
  • xumlidot 0.1.0

Ruby 2.6.6 のインストール

Ruby3 系だと動作しないので 2.6.6 をインストールします

  • rbenv install 2.6.6

インストール

bundler でインストールします
pry にも依存しているのでインストールします

  • bundle init
  • vim Gemfile
gem "xumlidot"
gem "pry"
  • bundle instsall

テストコード

gem を作成するときの構成っぽい感じで作成していますが test.rb だけ作成しても OK です

  • mkdir -p lib/user
  • vim lib/user.rb
require 'rubygems'
require 'fileutils'

require_relative 'user/test'

module User
end
  • vim lib/user/test.rb
module User
  class User
    def initialize(name, age)
      @name = name
      @age = age
    end

    def show
      puts "#{@name} => #{@age}"
    end

    attr_accessor :name, :age
  end

  class SuperUser < User
    def initialize(name, age)
      super(name, age)
      @admin = true
    end

    def show
      super
      puts @admin
    end
  end
end

動作確認

  • bundle exec xumlidot lib > test.dot
  • dot -Tpng test.dot -o test.png
  • open test.png

これで以下のようなクラス図が生成されていれば OK です

最後に

Ruby3 系ですでに進めてしまっているプロジェクトに適用できなくはないですがいろいろ面倒なので素直に諦めましょう

参考サイト

2021年9月17日金曜日

begoo でモデルを生成して JSON リクエストを受け取る方法

begoo でモデルを生成して JSON リクエストを受け取る方法

概要

beego には専用の CLI ツールがありこれを使うとプロジェクトの雛形を作成できます
シリアライズが必要な JSON などのデータはモデルが必要になり bee CLI を使うとその辺りのモデルも簡単に作成してくれます

今回は bee CLI を使ってプロジェクトの作成を行いモデルを使って POST メソッドで JSON を受け取る方法を紹介します

環境

  • macOS 11.5.2
  • golang 1.17
  • beego 2.0.1

bee コマンドのインストール

プロジェクトの作成

  • cd $GOPATH/src/github.com/hawksnowlog
  • bee new post_test

依存関係の解決

  • cd $GOPATH/src/github.com/hawksnowlog/post_test
  • go mod tidy

とりあえず動かす

  • cd $GOPATH/src/github.com/hawksnowlog/post_test
  • bee run

これで localhost:8080 にアクセスして以下の画面が表示されることを確認します

コントローラの編集

デフォルトのコントローラを編集して POST を受け取れるようにしてみます

  • cd $GOPATH/src/github.com/hawksnowlog/post_test
  • vim controllers/default.go
package controllers

import (
	"encoding/json"
	beego "github.com/beego/beego/v2/server/web"
)

type MainController struct {
	beego.Controller
}

type Person struct {
	Name string `json:"name"`
	Age  int    `json:"age"`
}

func (c *MainController) Post() {
	var p Person
	if err := json.Unmarshal(c.Ctx.Input.RequestBody, &p); err != nil {
		c.Ctx.WriteString("json parse error")
		return
	}
	c.Data["json"] = &p
	c.ServeJSON()
}

ポイントは Person 構造体を作成する点とそれを使って RequestBody から json.Unmarshal する点です

設定ファイルの修正

Input.RequestBody をコントラーラで参照する場合は config ファイルの変更も必要になります

copyrequestbody = true を追記します

  • cd $GOPATH/src/github.com/hawksnowlog/post_test
  • vim conf/app.conf
appname = post_test
httpport = 8080
runmode = dev
copyrequestbody = true

動作確認

これで再度 bee run しましょう

  • cd $GOPATH/src/github.com/hawksnowlog/post_test
  • bee run

あとは JSON + POST でリクエストするとリクエストした JSON が返却されるのが確認できると思います

  • curl -v -XPOST localhost:8080 -H 'content-type: application/json' -d '{"name":"hawksnowlog","age":100}'

最後に

beego を始める場合は bee new でプロジェクトをちゃんと作成してあげたほうが必要なディレクトリの作成もしてくれるので開発はしやすくなるかなと思います

参考サイト

2021年9月16日木曜日

beego 超入門

beego 超入門

概要

beego は golang 製の Web フレームワークです
今回はインストールから簡単な使い方を紹介します

環境

  • macOS 11.5.2
  • golang 1.17
  • beego 2.0.1

初期化

  • cd $GOPATH/src/github.com/hawksnowlog/test
  • go mod init

サンプルコード作成

  • cd $GOPATH/src/github.com/hawksnowlog/test
  • vim main.go
package main

import (
	"github.com/beego/beego/v2/server/web"
)

type MainController struct {
	web.Controller
}

func (this *MainController) Get() {
	this.Ctx.WriteString("hello world")
}

func main() {
	web.Router("/", &MainController{})
	web.Run()
}

依存関係解決

  • cd $GOPATH/src/github.com/hawksnowlog/test
  • go mod tidy

ビルド

  • cd $GOPATH/src/github.com/hawksnowlog/test
  • go build

動作確認

  • cd $GOPATH/src/github.com/hawksnowlog/test
  • ./test
  • curl localhost:8080

=> hello world

最後に

ドキュメントは中国語が多い印象です

参考サイト

2021年9月15日水曜日

go mod 超入門

go mod 超入門

概要

過去に go dep を使ったパッケージ管理方法を紹介しました
現在は go mod を使う方法が主流なので go mod を使ったパッケージ管理の方法を紹介します

環境

  • macOS 11.5.2
  • golang 1.17

サンプルコード

以下のコードを実行するために依存関係を go mod を使って解決します
Sirupsen/logrus という外部のパッケージを使っています

  • cd $GOPATH/src/github.com/hawksnowlog/test
  • vim main.go
package main

import (
	log "github.com/Sirupsen/logrus"
)

func main() {
	log.WithFields(log.Fields{
		"key": "value",
	}).Info("logrus test")
}

初期化

まずは初期化します
これで go.mod ファイルが作成されます

  • cd $GOPATH/src/github.com/hawksnowlog/test
  • go mod init

依存関係の解決

スクリプト内で使用しているパッケージを自動的に読み取ってインストールしてくれます
また go.mod が更新されて依存関係を自動で追記してくれる他 go.sum も生成されます

  • cd $GOPATH/src/github.com/hawksnowlog/test
  • go mod tidy
  • cat go.mod
module github.com/hawksnowlog/test

go 1.17

require github.com/sirupsen/logrus v1.8.1

require golang.org/x/sys v0.0.0-20191026070338-33540a1f6037 // indirect

ちなみに上記モジュールがインストールされるパスは

$GOPATH/pkg/mod/github.com/sirupsen/logrus@v1.8.1

でした

ビルド

あとはビルドするだけです
バイナリが生成されるか確認しましょう

  • cd $GOPATH/src/github.com/hawksnowlog/test
  • go build

実行

カレントにバイナリが生成されているので実行してみましょう
ちゃんと外部のモジュールが使われてエラーにならないことが確認できます

  • cd $GOPATH/src/github.com/hawksnowlog/test
  • ./test
INFO[0000] logrus test key=value

外部パッケージを追加したい場合は

普通に go get を使います

これで自動的に go.mod にも依存関係が追記されます

  • cat go.mod
module github.com/hawksnowlog/test

go 1.17

require github.com/sirupsen/logrus v1.8.1

require (
        github.com/gomodule/redigo v1.8.5 // indirect
        golang.org/x/sys v0.0.0-20191026070338-33540a1f6037 // indirect
)

あとは普通にスクリプト内で import すれば OK です
もしスクリプトのどこでも使われていない場合に再度 go mod tidy すると自動で依存関係を削除してくれます

最後に

go mod help で詳しい説明も確認できます
比較的新しい golang であれば標準で搭載されているのでこちらを使いましょう

参考サイト

2021年9月14日火曜日

marshmallow の post_dump の挙動を確認してみた

marshmallow の post_dump の挙動を確認してみた

概要

marshmallow の load と dump 時に自動的にコールされる pre_ post_ 系のデコレータの処理の挙動を確認してみました

環境

  • macOS 11.5.2
  • Python 3.8.3
  • marshmallow 3.13.0

インストール

  • pipenv install marshmallow

サンプルコード

from marshmallow import (
    Schema, pre_load, post_load, post_dump, fields
)

class User():
    def __init__(self, email, age):
        self.email = email
        self.age = age

class UserSchema(Schema):

    email = fields.Str(required=True)
    age = fields.Integer(required=True)

    @pre_load(pass_many=True)
    def remove_envelope(self, data, many, **kwargs):
        # ルート要素 (result or results) を data から取得する
        # 取得した data[namespace] は post_load で item に格納される
        namespace = 'results' if many else 'result'
        return data[namespace]

    @post_load
    def lowerstrip_email(self, item, many, **kwargs):
        # 各 item に格納されている値を加工する場合はこちらを使います
        # many=True の場合は自動的に複数回コールされます
        item['email'] = item['email'].lower().strip()
        return item

    @post_dump(pass_many=True)
    def add_envelope(self, data, many, **kwargs):
        # many=True の場合は results をルートキーとする dict を返却します
        namespace = 'results' if many else 'result'
        return {namespace: data}

schema = UserSchema()
result = schema.load({"result": {"age": "1", "email": "test1@mail"}})
print(result)
result = schema.load({"results": [{"age": "2", "email": "test2@mail"}, {"age": "3", "email": "test3@mail"}]}, many=True)
print(result)

user4 = User("test4@mail", 4)
result = schema.dump(user4)
print(result)
user5 = User("test5@mail", 5)
user6 = User("test6@mail", 6)
result = schema.dump([user5, user6], many=True)
print(result)

解説、挙動の確認

schema.load がコールされた場合には pre_load と post_load が自動的にコールされます
schema.dump がコールされた場合は pre_dump と post_dump が自動的にコールされます

load は dict -> dict の変換します
指定したキーの値配下の情報を取得しています

dump は class -> dict の変換をします
こちらのほうがよく使う手法になるかなと思います

pre_ ではデータの加工は行わず必要なデータの取得などを行います
post_ 側でデータを加工するので post_ 側に渡すデータを必ず return する必要があります
many=True の場合は post_ が自動的に複数回コールされて各要素分だけ処理されます

最後に

  • pre_ はデータの加工をする対象の抽出
  • post_ でデータの加工をする

というのが主な使い方になるかなと思います

参考サイト

2021年9月13日月曜日

emacs で HTTP リクエストを送信してみた

emacs で HTTP リクエストを送信してみた

概要

emacs 上で curl 的なことがしたい場合は request パッケージが使えます

環境

  • macOS 11.5.2
  • emacs 27.2
  • request 20210816.200

request のインストール

  • M-x package-list-packages
  • request を選択してインストール

.emacs 編集

動作確認は .emacs にリクエストを書いて行います
あとはバッファで eval-buffer します

GET

レスポンスは data に入ってきます
json-read を使うことで JSON レスポンスをパースしてくれます
assoc-default で指定したキー (params) の値を取得して表示しています

(require 'request)
(request "https://kaka-request-dumper.herokuapp.com/"
  :params '(("key" . "value") ("key2" . "value2"))
  :parser 'json-read
  :success (cl-function
            (lambda (&key data &allow-other-keys)
              (message "I sent: %S" (assoc-default 'params data)))))

POST

JSON を POST する場合は headers を設定すれば OK です

(require 'request)
(request "https://kaka-request-dumper.herokuapp.com/"
  :type "POST"
  :headers '(("Content-Type" . "application/json"))
  :data (json-encode '(("name" . "hawksnowlog") ("age" . "20")))
  :parser 'json-read
  :success (cl-function
            (lambda (&key data &allow-other-keys)
              (message "I sent: %S" (assoc-default 'body data)))))

最後に

外部からデータを取得したりするときに使えます
SDK などのパッケージを作るときには重宝するかもしれません

参考サイト