チャート式ruby-appendix-IV(rake)

\![Mac OS X-10.15.7](<https://img.shields.io/badge/MacOSX-10.15.7-brightgreen>) \![ruby-2.7.1p83](<https://img.shields.io/badge/ruby-2.7.1p83-brightgreen>) 


# make, antのruby版

前回のbundlerを少し思い出してください．

    rake install:local

とすると自動的にhogehogeがinstallされましたよね．そこで使ったrakeというコマンドが今日のお題です．

rakeはmakeやantのruby版です．ちょっとした仕事をさせるときに便利なように作られています．典型的な例は，

```ruby
task :default do
  system 'rake -T'
  exit
end

desc 'hello NAME'
task :hello do
  name = ARGV[1]
  puts "Hello #{name}!"
  exit
end
```

です．これをRakefileにカキコして，

    > rake

としてください．Rakefileが用意しているtask(仕事)が表示されます．qiitaとかmy\_helpでoptionなしで打った時の説明とよく似ているでしょ．

さて今書いた，Rakefileの中身を見ていきましょう．

-   descの後にはrake -Tとした時の説明文(description)
-   :defaultはrakeが引数なしで呼ばれた時の動作，
-   それ以外はoptionで呼ばれるtaskの名前
-   taskの中には標準のruby言語で，動作を記述

です．':'で始まる変数はsymbolと呼ばれるクラスで，名前の代わりをしてくれます．今は何のこっちゃでしょうが，そのうち多用するようになります．

rakeはDSL(Domain Specific Language)，つまり，その場に特有の言語を作っちゃおうという発想です．したがって純正のruby言語ではありませんが，ちょっとした仕事(task)を使いやすいように拡張されています．rakeの構文は，後で紹介するThorなどで使われています．


# system call

一番Rakefileに記述することの多い関数はsystemです，私は．これはsystemコマンドを起動する関数です．なんでかっていうと，手でやる作業をそのまま記述するから．例えば，gitであげたり(push)引っ張ってきたりする(pull)ときのコマンドって覚えにくくないですか？慣れるまではそのためにweb立ち上げて検索して，色の変わってるサイト読んで，そして最後まで繰って，そのコマンドを打ち込みます．それが普通だと私も思ってたんですよ．でも，達人プログラマたちは違うんですよね．覚えがいいのではなく，忘れそうなことはうまくメモしておくんです．例えば，Rakefileに

```ruby
desc 'git pull'
task :pull do
  p comm = "git pull origin main"
  system comm
  exit
end
```

と書いたら，これだけでもだいぶ使いやすくなるでしょ．

さらに，pullを失敗しても，pushでうまくやればいいので，

```ruby
desc 'git push'
task :push do
  p comm = "git add -A"
  system comm
  p comm = "git commit -m \'hoge\'"
  system comm
  p comm = "git pull origin main"
  system comm
  p comm = "git push origin main"
  system comm
  exit
end
```

といつもやってる作業を覚える代わりに，Rakefileに覚えさせます．コツは，p commで命令(command)が何かをpしておくこと．

さらに，幾つもcopyしたのは，バレると友達から蔑まされるので，こそっと隠します．

```ruby
desc 'git push'
task :push2 do
  ["git add -A",
   "git commit -m \'hoge\'",
   "git pull origin main",
   "git push origin main"].each do |comm|
    p comm  #puts comm.green after require 'colorize' 
    system comm
  end
  exit
end
```

さらに，commがどこに書いてあるかわからなくなるので講義の方でやるcolorizeを使うと見やすくなります．そうこうするうちに，gitの微妙なところも覚えちゃいます．


# command\_line

systemで使える外部のコマンドは動作が遅いので，たいがい，より高速で動かせるようにrubyの組み込み関数にも用意されています．例えば，lsにワイルドカードを使って呼び出すのは，Dir.globで代替できます．これのいいのは，「最初の５個で試す」とかができること．

```ruby
desc 'make list'
task :mk_list do
  # system 'ls -1 ../members/*/README.org'
  Dir.glob('../members/*/README.org')[0..4].each do |file|
    p file
    system "grep qiita_id #{file}"
  end
  exit
end
```

ここでorgのtableを作ろうとしているのですが，問題はsystemからの戻り値は出力ではなく，コマンドが成功したかどうかなんです．

なもんで，標準出力(stdout)などを取り出すのはcommand\_lineというgemを使います．いつものように，

    gem install command_line

としてください．これは，ruby 2.4以降だけで動作します．

```ruby
require 'command_line/global'
desc 'make list'
task :mk_list do
  targets = "../members/*/README.org"
  # system "ls -1 #{targets}"
  Dir.glob(targets)[0..5].each do |file|
    p file
    res = command_line "grep qiita_id #{file}"
    p res.stdout
  end
  exit
end
```

とすると取り出せます．

さてここから情報を取り出して

    # input
    "../members/daddygongon/README.org"
    "#+qiita_id: daddygongon\n"
    => # output
    | daddygongon | daddygongon|

のような変換を行います．

いくつかの動作をつけ加えて最終的に，

```ruby
require 'command_line/global'
desc 'make list'
task :mk_list do
  targets = "../members/*/README.org"
  i = 0
  Dir.glob(targets).each do |file|
    member = file.split('/')[2]
    dd = {}
    %i{qiita_id qiita_private}.each do |name|
      res = command_line "grep #{name.to_s} #{file}"
      res.stdout =~ /:\s*(.+)/ # regexp
      dd[name] = $1.to_s
    end
    next if dd[:qiita_id] == ''
    print " | [[https://qiita.com/#{dd[:qiita_id]}/private/#{dd[:qiita_private]}][#{member]}]]"
    i += 1
    puts "" if (i+1)%6==0
  end
  exit
end
```

としています．このようにして，filesから自動で情報抽出を行います．

regexpっと書いたところや，より一般的なデータ抽出の手法は来週説明します．


# org to\_html, to\_platex

my\_helpのところでemacs org-modeを紹介しました．qiita\_orgではそれをqiitaへcommand lineから出力していたのですが，より一般的にはhtmlやlatexへ出力するcommandが用意されています．

    c-c c-e ho # export as [h]tml, [o]ut
    c-c c-e ll # export [l]atex, [l]atex 

などでそれらのフォーマットへの変換ができます．c-cというのがmajor-modeへのcommandという意味だとわかってくるのでは？

ただこのままの出力では見にくいです．そこで，htmlではreadtheorgというformatをお勧めします．latexではheaderの書き換えを行い，必要なフォーマットにします．


## html

htmlで出力するには，<https://github.com/fniessen/org-html-themes>を参照してください．readtheorgを推薦します．次のtheme-readtheorg.setupファイル

```org
# -*- mode: org; -*-

#+HTML_HEAD: <link rel="stylesheet" type="text/css" href="https://fniessen.github.io/org-html-themes/styles/readtheorg/css/htmlize.css"/>
#+HTML_HEAD: <link rel="stylesheet" type="text/css" href="https://fniessen.github.io/org-html-themes/styles/readtheorg/css/readtheorg.css"/>

#+HTML_HEAD: <script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.3/jquery.min.js"></script>
#+HTML_HEAD: <script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.4/js/bootstrap.min.js"></script>
#+HTML_HEAD: <script type="text/javascript" src="https://fniessen.github.io/org-html-themes/styles/lib/js/jquery.stickytableheaders.min.js"></script>
#+HTML_HEAD: <script type="text/javascript" src="https://fniessen.github.io/org-html-themes/styles/readtheorg/js/readtheorg.js"></script>
```

を~/.emacs.d/org-mode/においてください．

```org
#+SETUPFILE: ~/.emacs.d/org-mode/theme-readtheorg.setup
```

と書こうとしているorg-fileのheaderに書き加えてください．このあとexport hoすると出来上がりです．


## latex

latexに関しては，使う必要がある人だけ以下の手順を試して見てください．

org-modeが用意しているlispを使うと相当複雑なことができます．でも，lispを覚える必要があるので少し面倒で，私の余命をかけるのはちょっとリスクがありそうです．そこで，先ほど紹介したRakefileにheaderを置き換える命令を追加します．例えば，中間審査のlatexファイルを使う例が，docs/latex\_exampleにあります．

こういう繰り返し使うコマンドを，一発で実行できるのがrakeのいいところ．rakeに一括で処理させると無駄なファイルも一緒にやっちゃいます．でも，冗長な動作でかかってしまう時間を気にするよりも，codingやコマンドを思い出すのにかかるコストを節約することを心がけてください．特に，卒論ではたくさんの研究室でlatexを使ってはるでしょうから，ぜひ，試してみてください．それと，このexampleは西谷研独自に作ってきたものなので，もっといい手があれば教えてください．



------
 - **source** ~/git_hub/ruby_docs/chart_style_ruby/c04_rake.org