2018/12/21

umeboshi開発中

日本語名縛りでライブラリを作る

umeboshiは、Rustで現在作成を始めたもので、これまた海外の方々に「ウメボシ」と言わせたいというちょっとした願望を持ちつつ命名しました。ひょっとしたら「ユーミボゥシ」と発音されるかもしれませんが、それはそれで面白い。

さてこのUmeboshiですが、Pythonのインタラクティブシェルのようなものを作ってみようと思い、作成しました。プライマリープロンプトは当然梅干し色に近いものにしました。その際使わせていただいたライブラリはtermionです。色付けに関してのみ使っているので、他の機能はまだ使っておりません。
現在umeboshiは、5つのことができます。
  • quit
  • help
  • version
  • echo
  • sum
quit・help・versionについては、その名の通りのコマンドです。そしてecho・sumに関しては、まず%を打ってから使うことになります。この%は「関数を使いますよ」のマークということにしています。ひょっとしたらなくても良いかもしれませんが、メインループの部分のコードが、関数を増やすたびにごちゃついてしまう可能性が出てくるので使っています。
コードは極々単純で、文字列を受け取り、空白で区切りVecにし、各要素とマッチする処理をし、表示するという形になっています。
echoは、echo以降の文字列をそのまま表示するようにしており、sumはsum以降の数値の合計を表示します。表示はResultのOk()またはErr()の形のまま表示します。入力された数値(文字列型)が数値として計算できるか否かはis_number()という関数を設けており、その結果が、つまり、すべて数値として計算できる場合のみ、Ok(結果)という形で表示し、もし数値でないものがある場合は、Err(Contain not-number)が表示されます。
今後開発を進めていくうちに、多くの不便・不具合が出そうな予感満載ですが、思考錯誤しながら作っていこうと思います。一応メインとなるコードは以下のようになっております。その他はGitHubで見れます。私のコードはしょぼい感じですが、termionの使いやすさを少しでも伝えることができれば良いかなと思います。定数TITLEの部分の枠がこのブログではズレておりますが、お気になさらず…

use std::io::Write;
use std::io;
use termion::{color, style};
use super::calc;

const TITLE: &str = r#"
    *--------------*
    |umeboshi shell|
    *--------------*
"#;
const VERSION: &str = "0.1.0";
const PRIMARY_PROMPT: &str = "umeboshi>>";
const HELP: &str = r#"
    [Usage]
    quit                close shell.
    help or -h          help.
    version or -v       version information.
    % [command]         % is calling function.
    % echo [text]       output string.
    % sum 1 2 3 ....    output the sum.
"#;

// Main Loop 
pub fn main_loop() {
    println!(
        "{}{}{}", 
        color::Fg(color::LightRed), 
        TITLE, 
        style::Reset
    );

    loop {
        let mut s = String::new();
        print!(
            "{}{}{} ", 
            color::Fg(color::LightRed),
            PRIMARY_PROMPT, 
            style::Reset, 
        );
        io::stdout().flush().expect("Couldn't flush stdout");
        io::stdin().read_line(&mut s).expect("Failed.");

        let v: Vec<&str> = s.trim().split_whitespace().collect();

        match &v[0] {
            &"quit" => {
                println!("Bye!!");
                break;
            },
            &"version"|&"-v" => {
                println!("{}", VERSION);
                continue;
            },
            &"help"|&"-h" => {
                println!("{}{}{}", color::Fg(color::Cyan), HELP, style::Reset);
                continue;
            },
            &"%" => {
                println!("{}", bind_func(&v));
                continue;
            },
            _ => {
                println!(
                    "\tPlease input{} {} help{}", 
                    color::Fg(color::LightYellow), 
                    PRIMARY_PROMPT, 
                    style::Reset
                );
                continue;
            }
        }
    }
}

// Distinction of some functions.
fn bind_func<'b>(v: &Vec<&'b str>) -> String {
    match &v[1] {
        &"echo" => format!("{}", v[2..].join(&" ")),
        &"sum" => format!("{:?}", calc::sum(v.to_vec())),
        _ => format!("Not exist its command."),
    }
}
また同時進行で、HobitというNimを使った似たようなものを開発しています。こちらの名前はロード・オブ・ザ・リングでお馴染みのホビットから拝借しました。Nimがニムロッドという王の名前が由来だそうなので、その名に寄せてみました。こちらに関しては別の機会に。