LoginSignup
0
0

More than 1 year has passed since last update.

Bash で alias_method_chain を実装する

Last updated at Posted at 2022-07-24

Ruby on Rails (ActiveSupport) の alias_method_chain1 を Bash で使えるように実装しました。ソースコードは GitHub (https://github.com/suzuki-kei/bash-alias-method-chain) で公開しています。

(Ruby) alias_method_chain とは

Ruby on Rails (ActiveSupport) の alias_method_chain を使うと、既存のメソッドの前後に処理を追加できます:

module Hello

    def hello(name)
        puts "Hello #{name}"
    end

    def hello_with_trace(name)
        puts '---- BEGIN ----'
        hello_without_trace(name)
        puts '---- END ----'
    end

    # hello_without_trace は元の hello のエイリアスになり,
    # 新しく hello は hello_with_trace のエイリアスになる.
    alias_method_chain :hello, :trace

end

hello と呼び出すと hello_with_trace が実行されます:

> include Hello
> hello('Taro')
---- BEGIN ----
Hello Taro
---- END ----

(Bash) alias_method_chain

以下のように実装しました。

alias-method-chain.sh
# スクリプト中で alias を使用する場合に必要.
shopt -s expand_aliases

function alias_method_chain {
    local -r name="$1"
    local -r functionality="$2"

    case $(type -t "$name") in
        alias)
            eval "$(cat <<EOS
                function ${name}_without_${functionality} {
                    $(type "$name" | sed -r "s/^$name is aliased to \`|'$//g") "\$@"
                }
                builtin alias ${name}=${name}_with_${functionality}
EOS)"
            return 0
            ;;
        builtin | file | function)
            eval "$(cat <<EOS
                function ${name}_without_${functionality} {
                    ${name} "\$@"
                }
                builtin alias ${name}=${name}_with_${functionality}
EOS)"
            return 0
            ;;
        *)  
            echo "ERROR: $(type -t '${name}') is unsupported type." >&2
            return 1
            ;;
    esac
}

使用例:

alias-method-chain-test.sh
source alias-method-chain.sh

# スクリプト中で alias を使用する場合に必要.
shopt -s expand_aliases

function hello {
    echo "Hello $1" 
}   

function hello_with_trace {
    echo '---- BEGIN ----'
    hello_without_trace "$@"
    echo '---- END ----'
}   

alias_method_chain hello trace

hello 'Taro'

実行結果:

---- BEGIN ----
Hello Taro
---- END ----

解説

スクリプト中で alias を使う方法

Bash スクリプトの中で alias を使う場合は以下の指定が必要です。

# スクリプト中で alias を使用する場合に必要.
shopt -s expand_aliases

...

type の結果で分岐する

Bash のビルトイン関数である type を使うと、指定した名前がどのように解釈されるのか調べることができます。

$ type bash
bash is /bin/bash

-t オプションで種類が分かります。type -t の結果は alias, keyword, function, builtin, file もしくは空文字列になります。

$ type -t bash
file

この結果で alias_method_chain の処理を分岐します(種類によって実装を変える必要があるため)。

alias を置き換える

alias を置き換える実装は以下のようにしました。これは type の出力結果に依存してしまっているので不本意です。他に良い方法があれば改善したい部分です。

...
    case $(type -t "$name") in
        alias)
            eval "$(cat <<EOS
                function ${name}_without_${functionality} {
                    $(type "$name" | sed -r "s/^$name is aliased to \`|'$//g") "\$@"
                }
                builtin alias ${name}=${name}_with_${functionality}
EOS)"
            return 0
            ;;
...
  1. alias_method_chain は Ruby on Rains 5 で非推奨になりましたが、実現したいことが伝わりやすいと思い alias_method_chain と書きました。

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0