以前powerモードの一部の機能紹介しましたが、なんだか2.9.0でREPLのpowerモードの機能がさらに増えていて、しかもかなり便利なものを見つけたので紹介
まず
:power
と打つとpowerモードという、コンパイラ内部にアクセスして、あんなことやこんなことができる変態的なモードになります。2.8.1だと以下のような感じだったのですが
scala> :power ** Power User mode enabled - BEEP BOOP ** ** scala.tools.nsc._ has been imported ** ** New vals! Try repl, global, power ** ** New cmds! :help to discover them ** ** New defs! Type power.<tab> to reveal ** scala> :help All commands can be abbreviated - for example :he instead of :help. :cp <arg> add an entry (jar or directory) to the classpath :help print this help message :history [arg] show the history (optional arg: lines to show) :h? <line> search the history :load <arg> load and interpret a Scala file :power enable power user mode :quit exit the interpreter :replay reset execution and replay all previous commands :sh <line> fork a shell and run a command :silent disable/enable automatic printing of results :completions <arg> generate list of completions for a given String :dump displays a view of the interpreter's internal state
2.9.0だと以下のように微妙に違います
scala> :power ** Power User mode enabled - BEEP BOOP WHIR ** ** scala.tools.nsc._ has been imported ** ** global._ and definitions._ also imported ** ** New vals! Try repl, intp, global, power ** ** New cmds! :help to discover them ** ** New defs! Type power.<tab> to reveal ** scala> :help All commands can be abbreviated, e.g. :he instead of :help. Those marked with a * have more detailed help, e.g. :help imports. :cp <path> add a jar or directory to the classpath :help [command] print this summary or command-specific help :history [num] show the history (optional num is commands to show) :h? <string> search the history :imports [name name ...] show import history, identifying sources of names :implicits [-v] show the implicits in scope :javap <path|class> disassemble a file or class name :keybindings show how ctrl-[A-Z] and other keys are bound :load <path> load and interpret a Scala file :paste enter paste mode: all input up to ctrl-D compiled together :power enable power user mode :quit exit the interpreter :replay reset execution and replay all previous commands :sh <command line> run a shell command (result is implicitly => List[String]) :silent disable/enable automatic printing of results :type <expr> display the type of an expression without evaluating it :dump displays a view of the interpreter's internal state :phase <phase> set the implicit phase for power commands :wrap <method> * name of method to wrap around each repl line
で今回紹介するのが、wrapっていうやつ。
wrapって増えてる、なにこれ(´・ω・`)?って偶然見つけたんですが。ScalaのREPLは
:help コマンド名
と打つと以下のように、コマンド自体のhelpが表示されます。で、wrapの説明↓
scala> :help wrap :wrap :wrap clear :wrap <method> Installs a wrapper around each line entered into the repl. Currently it must be the simple name of an existing method with the specific signature shown in the following example. def timed[T](body: => T): T = { val start = System.nanoTime try body finally println((System.nanoTime - start) + " nanos elapsed.") } :wrap timed If given no argument, :wrap names the wrapper installed. An argument of clear will remove the wrapper if any is active. Note that wrappers do not compose (a new one replaces the old one) and also that the :phase command uses the same machinery, so setting :wrap will clear any :phase setting.
簡単にいうと、以下のように
def hoge[A](body: => A):A = { /* メソッド本体 */}
- 型引数を1つとる
- 引数は名前渡しで、型引数の型のものを1つ
- 戻り値の型も引数の型と同じ
というシグネチャのメソッドを定義して、登録することによって、REPLの式を評価するたび毎回その関数にwrapされて実行されるということができるようです!
上記のヘルプの例は、毎回 nano 秒単位で実行時間を計る関数の例ですね。登録するのはこんな感じ。
scala> def timed[T](body: => T): T = { //まず関数自体定義 | val start = System.nanoTime | try body | finally println((System.nanoTime - start) + " nanos elapsed.") | } timed: [T](body: => T)T
そして、関数を登録
scala> :wrap timed Set wrapper to 'timed'
普通の式を実行
scala> 1 to 10 foreach println 1 2 3 4 5 6 7 8 9 10 1477666 nanos elapsed.
実行時間が表示されてる!!!
解除もできる↓
scala> :wrap clear Cleared execution wrapper.
表示されなくなる↓
scala> Long.MinValue.toHexString.map{_+12312 toChar}.mkString res2: String = ぐえええええええええええええええ
この時間計るやつとか登録しておけばかなり便利じゃね?
関数の内容はなんでもいいのでこんなことも↓
scala> def ababa[A](body: => A):A ={ val r = body println(Long.MaxValue.toHexString.map{_ + 12298 toChar}.mkString) r } ababa: [A](body: => A)A scala> :wrap ababa Set wrapper to 'ababa' scala> 1 to 10 sum ぁばばばばばばばばばばばばばばば res3: Int = 55
毎回全自動で「ぁばばばばばばばばばばばばばばば」が表示される、超うざいオリジナルREPLが( ´∀`*)
他にも、「wrapの関数で、REPLの評価結果を自動で全部ファイルに保存」とか色々工夫次第で夢がひろがりんぐ(´Д`*)
みんなもっと、powerモードごにょごにょして、裏技発見しようぜ(`・ω・´)