hikiutils 0.2.3.13 → 0.2.3.14
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/hikiutils.gemspec +2 -1
- data/hikiutils_bob/Rakefile +30 -16
- data/hikiutils_bob/code.hiki +9 -30
- data/hikiutils_bob/figs/hikiutils_bob.002.jpeg +0 -0
- data/hikiutils_bob/figs/hikiutils_bob.007.jpeg +0 -0
- data/hikiutils_bob/figs/hikiutils_bob.pdf +0 -0
- data/hikiutils_bob/hikiutils_bob/hikiutils_bob.002.jpeg +0 -0
- data/hikiutils_bob/hikiutils_bob/hikiutils_bob.007.jpeg +0 -0
- data/hikiutils_bob/hikiutils_bob.key +0 -0
- data/hikiutils_bob/latex_all.hiki +33 -8
- data/hikiutils_bob/latex_dir/code.aux +7 -14
- data/hikiutils_bob/latex_dir/code.log +28 -0
- data/hikiutils_bob/latex_dir/code.tex +13 -31
- data/hikiutils_bob/latex_dir/hikiutils_bob.log +59 -50
- data/hikiutils_bob/latex_dir/hikiutils_bob.pdf +0 -0
- data/hikiutils_bob/latex_dir/hikiutils_bob.synctex.gz +0 -0
- data/hikiutils_bob/latex_dir/hikiutils_bob.toc +29 -29
- data/hikiutils_bob/latex_dir/latex_all.aux +19 -16
- data/hikiutils_bob/latex_dir/latex_all.log +28 -0
- data/hikiutils_bob/latex_dir/latex_all.tex +34 -9
- data/hikiutils_bob/latex_dir/sync.aux +16 -16
- data/hikiutils_bob/latex_dir/sync.tex +4 -4
- data/hikiutils_yamane/Rakefile +14 -2
- data/hikiutils_yamane/abstract.hiki +3 -3
- data/hikiutils_yamane/discussion.hiki +9 -0
- data/hikiutils_yamane/hikiutils_yamane.hiki +8 -10
- data/hikiutils_yamane/introduction.hiki +1 -1
- data/hikiutils_yamane/latex_dir/abstract.tex +3 -3
- data/hikiutils_yamane/latex_dir/{%CA%FD/313/241.aux → discussion.aux} +8 -7
- data/hikiutils_yamane/latex_dir/discussion.tex +9 -0
- data/hikiutils_yamane/latex_dir/hikiutils_yamane.aux +3 -6
- data/hikiutils_yamane/latex_dir/hikiutils_yamane.log +50 -59
- data/hikiutils_yamane/latex_dir/hikiutils_yamane.pdf +0 -0
- data/hikiutils_yamane/latex_dir/hikiutils_yamane.synctex.gz +0 -0
- data/hikiutils_yamane/latex_dir/hikiutils_yamane.tex +4 -7
- data/hikiutils_yamane/latex_dir/hikiutils_yamane.toc +21 -21
- data/hikiutils_yamane/latex_dir/introduction.tex +1 -1
- data/hikiutils_yamane/latex_dir/method.aux +46 -0
- data/hikiutils_yamane/latex_dir/method.tex +247 -0
- data/hikiutils_yamane/latex_dir/results.aux +49 -0
- data/hikiutils_yamane/latex_dir/results.tex +249 -0
- data/hikiutils_yamane/method.hiki +234 -0
- data/hikiutils_yamane/results.hiki +225 -0
- data/hikiutils_yamane/toc.hiki +0 -1
- data/lib/hikiutils/version.rb +1 -1
- data/lib/hikiutils_thor.rb~ +37 -37
- data/lib/templates/Rakefile_hiki_sync +32 -17
- data/lib/templates/mi_key_bind_setting +1 -0
- metadata +33 -19
- data/hikiutils_yamane/Rakefile~ +0 -477
- data/hikiutils_yamane/command.hiki +0 -111
- data/hikiutils_yamane/compare.hiki +0 -116
- data/hikiutils_yamane/latex_dir/command.aux +0 -35
- data/hikiutils_yamane/latex_dir/command.log +0 -0
- data/hikiutils_yamane/latex_dir/command.tex +0 -123
- data/hikiutils_yamane/latex_dir/compare.aux +0 -30
- data/hikiutils_yamane/latex_dir/compare.tex +0 -123
- data/hikiutils_yamane/latex_dir/optparse.aux +0 -31
- data/hikiutils_yamane/latex_dir/optparse.tex +0 -119
- data/hikiutils_yamane/latex_dir/thor.aux +0 -32
- data/hikiutils_yamane/latex_dir/thor.tex +0 -110
- data/hikiutils_yamane/optparse.hiki +0 -114
- data/hikiutils_yamane/thor.hiki +0 -107
@@ -0,0 +1,249 @@
|
|
1
|
+
|
2
|
+
\section{結果}
|
3
|
+
\subsection{コマンドの命名原則}
|
4
|
+
機能ごとの動作はコマンドのオプションによって指定されます.
|
5
|
+
このオプションにどのような名前をつけるかは,どれだけコマンドを覚えやすいかという
|
6
|
+
意味で重要です.コマンドの振る舞いを的確に表す名称をつける必要があります.
|
7
|
+
|
8
|
+
この振る舞いとしてもっとも受け入れやすいのがshellで用意されているコマンドです.
|
9
|
+
pwd, ls, rm, touch, openなどはもっとも直感的に動作がわかるコマンドです.
|
10
|
+
hikiutilsの振る舞いを予測できるシェルコマンドと同じ名前でオプションを提供する
|
11
|
+
ようにします.
|
12
|
+
|
13
|
+
\subsubsection{hikiutilsの想定利用形態}
|
14
|
+
ここでhikiutilsがあらかじめ想定している利用形態を解説しておきます.
|
15
|
+
|
16
|
+
\begin{figure}[htbp]\begin{center}
|
17
|
+
\includegraphics[width=10cm,bb= 0 0 737 553]{../figs/./hikiutils_yamane.002.jpg}
|
18
|
+
\caption{hikiutilsがあらかじめ想定している利用形態.}
|
19
|
+
\label{fig:002}
|
20
|
+
\label{default}\end{center}\end{figure}
|
21
|
+
hikiutilsは,
|
22
|
+
|
23
|
+
\begin{itemize}
|
24
|
+
\item local PCとglobal serverとが用意されており,
|
25
|
+
\item それらのデータをrsyncで同期する
|
26
|
+
\end{itemize}
|
27
|
+
ことで動作することを想定しています.これは,ネットに繋がっていないオフラインの状況でも
|
28
|
+
テキストなどの編集が可能で,さらに不用意な書き換えを防ぐための機構です.さらに,
|
29
|
+
どちらもが何かあった時のバックアップともなって,ミスによる手戻りを防いでいます.
|
30
|
+
|
31
|
+
これらの設定は,~/.hikircにyaml形式で記述・保存されています.
|
32
|
+
\begin{lstlisting}[style=,basicstyle={\scriptsize\ttfamily}]
|
33
|
+
bob% cat ~/.hikirc
|
34
|
+
:srcs:
|
35
|
+
- :nick_name: new_ist
|
36
|
+
:local_dir: "/Users/bob/Sites/new_ist_data/ist_data"
|
37
|
+
:local_uri: http://localhost/ist
|
38
|
+
:global_dir: nishitani@ist.ksc.kwansei.ac.jp:/home/nishitani/new_ist_data/ist_data
|
39
|
+
:global_uri: http://ist.ksc.kwansei.ac.jp/~nishitani/
|
40
|
+
- :nick_name: dmz0
|
41
|
+
:local_dir: "/Users/bob/Sites/nishitani0/Internal/data"
|
42
|
+
:local_uri: http://localhost/~bob/nishitani0/Internal
|
43
|
+
:global_dir: bob@dmz0:/Users/bob/Sites/nishitani0/Internal/data
|
44
|
+
:global_uri: http://nishitani0.kwansei.ac.jp/~bob/nishitani0/Internal
|
45
|
+
\end{lstlisting}
|
46
|
+
また,一般的に一人のユーザがいくつものまとまりとしてのlocal-globalペアを
|
47
|
+
保持して管理することが普通です.それぞれにnicke\_nameをつけて管理しています.
|
48
|
+
\begin{lstlisting}[style=,basicstyle={\scriptsize\ttfamily}]
|
49
|
+
bob% hiki -s
|
50
|
+
hikiutils: provide utilities for helping hiki editing.
|
51
|
+
"open -a mi"
|
52
|
+
target_no:1
|
53
|
+
editor_command:open -a mi
|
54
|
+
id | name | local directory | global uri
|
55
|
+
-----------------------------------------------------------------------------
|
56
|
+
0 | new_ist | /Users/bob/Sites/new_ist_data/ist_data | http://ist.ksc.k
|
57
|
+
*1 | dmz0 | /Users/bob/Sites/nishitani0/Internal/data | http://nishitani
|
58
|
+
2 | ist | /Users/bob/Sites/hiki-data/data | http://ist.ksc.k
|
59
|
+
3 | new_maple | /Users/bob/Sites/new_ist_data/maple_hiki_d| http://ist.ksc.k
|
60
|
+
\end{lstlisting}
|
61
|
+
とすると,それらの一覧と,いまtargetにしているnick\_nameディレクリが表示されます.
|
62
|
+
|
63
|
+
\subsubsection{コメンド名と振る舞いの詳細}
|
64
|
+
検討の結果コマンドを以下の表\ref{table:ShellOption}のとおり書き換えることとします.
|
65
|
+
上部に記した,特によく使うコマンドに関しては,shellでよく使われるコマンド名と一致するにようにしました.
|
66
|
+
|
67
|
+
\begin{table}[htbp]\begin{center}
|
68
|
+
\caption{コマンドオプションとshellコマンドの対応.}
|
69
|
+
\label{table:ShellOption}
|
70
|
+
\begin{tabular}{llll}
|
71
|
+
\hline
|
72
|
+
変更前 &変更後 &動作の解説 \\ \hline
|
73
|
+
edit FILE &open &open file \\
|
74
|
+
list [FILE] &ls &list files \\
|
75
|
+
rsync &rsync &rsync files \\
|
76
|
+
update FILE &touch &update file \\
|
77
|
+
show &pwd &show nick\_names \\
|
78
|
+
target VAL &cd &targetを変える,cdとのメタファ \\
|
79
|
+
& \\
|
80
|
+
move [FILE] &mv &move file \\
|
81
|
+
remove [FILE] &rm &remove files \\
|
82
|
+
add & &add sources info \\
|
83
|
+
checkdb & &check database file \\
|
84
|
+
datebase FILE &db &read datebase file \\
|
85
|
+
display FILE &show &display converted hikifile \\
|
86
|
+
euc FILE & &translate file to euc \\
|
87
|
+
help [COMMAND] &-h &Describe available commands \\
|
88
|
+
version &-v &show program version \\
|
89
|
+
\hline
|
90
|
+
\end{tabular}
|
91
|
+
\label{default}
|
92
|
+
\end{center}\end{table}
|
93
|
+
%for inserting separate lines, use \hline, \cline{2-3} etc.
|
94
|
+
|
95
|
+
それぞれの意図を動作の解説として記述しています.
|
96
|
+
|
97
|
+
\paragraph{open FILE}
|
98
|
+
ファイルを編集のためにeditorでopen.Editorは~/.hikircに
|
99
|
+
\begin{quote}\begin{verbatim}
|
100
|
+
:editor_command: open -a mi
|
101
|
+
\end{verbatim}\end{quote}
|
102
|
+
として保存されている.open -a miをemacsなどに適宜変更して使用.
|
103
|
+
|
104
|
+
\paragraph{ls [FILE]}
|
105
|
+
local\_dirにあるファイル名を[FILE*]として表示.例えば,hikiutils\_yamane以下の拡張子が
|
106
|
+
ついたファイルを表示.hikiシステムではtextディレクトリーは階層構造を取ることができない.
|
107
|
+
西谷研ではdirectoryの代わりにスネーク表記で階層構造を表している.
|
108
|
+
|
109
|
+
\paragraph{rsync}
|
110
|
+
local\_dirの内容をglobal\_dirにrsyncする.逆方向は同期に誤差が生じたり,permissionが
|
111
|
+
おかしくなるので,現在のところ一方向の同期のみとしている.したがって,作業手順としては
|
112
|
+
テキストの変更はlocal\_dirで読み行うようにしている.
|
113
|
+
|
114
|
+
\paragraph{touch FILE}
|
115
|
+
loccal\_dirで書き換えたFILEの内容をlocal\_uriに反映させ,ブラウザで表示.シェルコマンドの
|
116
|
+
touchによって,変更時間を現在に変え,最新状態とするのに似せてコマンド名をtouchとしている.
|
117
|
+
|
118
|
+
\paragraph{pwd}
|
119
|
+
nick\_nameの一覧とtargetを表示,current targetをcurrent dirとみなして,
|
120
|
+
コマンド名をpwdとした.
|
121
|
+
|
122
|
+
\paragraph{cd VAL}
|
123
|
+
targetを変える,change directoryとのメタファ.ただし,いまのところnick\_nameでは
|
124
|
+
対応しておらず,nick\_nameの番号をVAL入力することで変更する.
|
125
|
+
|
126
|
+
\subsection{Thorによる実装}
|
127
|
+
手法のところで概観した通り,Thorを用いることで記述の簡略化が期待できる.ここでは,実際に書き換える前後,すなわちoptparse版とThor版の対応するコードを比較することで,以下の具体的な違い
|
128
|
+
|
129
|
+
\begin{itemize}
|
130
|
+
\item クラス初期化
|
131
|
+
\item コマンド定義
|
132
|
+
\item CLIの実行プロセス
|
133
|
+
\end{itemize}
|
134
|
+
について詳しく検討を行う.
|
135
|
+
|
136
|
+
\subsubsection{クラス初期化}
|
137
|
+
\begin{figure}[htbp]\begin{center}
|
138
|
+
\includegraphics[width=10cm,bb= 0 0 737 553]{../figs/./hikiutils_yamane.003.jpg}
|
139
|
+
\caption{Thorのinitializeでのコード}
|
140
|
+
\label{default}\end{center}\end{figure}
|
141
|
+
Thorのinitializeでのコードはつぎの通りである.
|
142
|
+
|
143
|
+
\begin{enumerate}
|
144
|
+
\item Hikithor::CLI.start(ARGV)が呼ばれる
|
145
|
+
\item initializeメソッドが呼ばれる
|
146
|
+
\item これではThorのinitializeメソッドが呼ばれない
|
147
|
+
\item superを書くことでThorのinitializeメソッドが呼ばれる
|
148
|
+
\end{enumerate}
|
149
|
+
optparseではrequireでoptparseを呼びoptparseのinitializeを定義する必要はないが,Thorはinitializeを定義する必要がある.Thorの定義方法はrequireでThorを呼びCLIクラスで継承し,initializeメソッドにsuperを書くことでThorのinitializeが呼ばれる.initializeメソッド内ではThorの初期設定がされていないため,スーパークラスのメソッドを読み出してくれるsuperを書き加えることで図のようにinitializeメソッド内でThorのinitilalizeメソッドが呼ばれ定義される.
|
150
|
+
\begin{lstlisting}[style=customRuby,basicstyle={\scriptsize\ttfamily}]
|
151
|
+
|
152
|
+
module Hikithor
|
153
|
+
|
154
|
+
DATA_FILE=File.join(ENV['HOME'],'.hikirc')
|
155
|
+
attr_accessor :src, :target, :editor_command, :browser, :data_name, :l_dir
|
156
|
+
|
157
|
+
class CLI < Thor
|
158
|
+
def initialize(*args)
|
159
|
+
super
|
160
|
+
@data_name=['nick_name','local_dir','local_uri','global_dir','global_uri']
|
161
|
+
data_path = File.join(ENV['HOME'], '.hikirc')
|
162
|
+
DataFiles.prepare(data_path)
|
163
|
+
|
164
|
+
...以下略...
|
165
|
+
end
|
166
|
+
\end{lstlisting}
|
167
|
+
\subsubsection{コマンド定義}
|
168
|
+
Thorではoptparseのような登録処理はない.図\ref{fig:004}にある通りにコマンドが記述される.
|
169
|
+
|
170
|
+
\begin{figure}[htbp]\begin{center}
|
171
|
+
\includegraphics[width=10cm,bb= 0 0 737 553]{../figs/./hikiutils_yamane.004.jpg}
|
172
|
+
\caption{Thorにおけるコマンド記述のひな形.}
|
173
|
+
\label{fig:004}
|
174
|
+
\label{default}\end{center}\end{figure}
|
175
|
+
それらは以下のように構成される.
|
176
|
+
|
177
|
+
\begin{enumerate}
|
178
|
+
\item desc以降にコマンド名と,その説明が記述される.これらはコマンドhelpで一覧として表示させる
|
179
|
+
\item mapによって別のコマンド名でも実行できるように定義される.
|
180
|
+
\item defで定義されたメソッドの実行コード
|
181
|
+
\end{enumerate}
|
182
|
+
Thorではdescで一覧を表示されるコマンド名,コマンドの説明を登録する.しかし,ここで記述したコマンドは単に一覧で表示させるためのものであり,実際に実行される時に呼び出すコマンド名は,defで定義された名前である.Thorでは処理実行を行うメソッド名がコマンド名となり,コマンド名1つが対応する.
|
183
|
+
|
184
|
+
これに別名を与えるために利用されるキーワードがmapである.
|
185
|
+
\begin{quote}\begin{verbatim}
|
186
|
+
map A => B
|
187
|
+
\end{verbatim}\end{quote}
|
188
|
+
mapとはBと呼ばれるメソッドをAでも呼べるようにしてくれるものである.
|
189
|
+
よって,これを使うことでコマンドの別名を指定することができる.
|
190
|
+
\begin{lstlisting}[style=customRuby,basicstyle={\scriptsize\ttfamily}]
|
191
|
+
desc 'show,--show', 'show sources'
|
192
|
+
map "--show" => "show"
|
193
|
+
def show
|
194
|
+
printf("target_no:%i\n",@src[:target])
|
195
|
+
printf("editor_command:%s\n",@src[:editor_command])
|
196
|
+
,,,以下略...
|
197
|
+
end
|
198
|
+
\end{lstlisting}
|
199
|
+
以上より,Thorではコマンドの指定と処理にはdesc,map,処理メソッドだけで済む.optparseではコマンドを登録するためのメソッドと処理メソッドの両方が必要になっていた.一方Thorでは,処理メソッドが直接コマンド名となるため記述が簡潔になる.
|
200
|
+
|
201
|
+
\subsubsection{CLIの実行プロセス}
|
202
|
+
CLIの実行プロセスは図\ref{fig:006}の通りである.
|
203
|
+
|
204
|
+
\begin{figure}[htbp]\begin{center}
|
205
|
+
\includegraphics[width=10cm,bb= 0 0 737 553]{../figs/./hikiutils_yamane.006.jpg}
|
206
|
+
\caption{CLIの実行プロセス.}
|
207
|
+
\label{fig:006}
|
208
|
+
\label{default}\end{center}\end{figure}
|
209
|
+
Thorにおけるcliの実行プロセスは次の通りである.
|
210
|
+
|
211
|
+
\begin{enumerate}
|
212
|
+
\item hiki\_thorのHikithor::CLI.start(ARGV)でhikiutils\_thor.rbのCLIクラスを呼ぶ
|
213
|
+
\item hikiutils\_thor.rbのCLIクラスのメソッドを順に実行していく
|
214
|
+
\end{enumerate}
|
215
|
+
Thorではstart(ARGV)を呼び出すことでCLIを開始する.Hikithor::CLI.start(ARGV)を実行されることによりrequireで呼ばれているhikiutils\_thor.rbのCLIコマンドを順に実行する.そして,入力されたコマンドと一致するメソッドを探し,そのコマンドの処理が実行される.
|
216
|
+
|
217
|
+
exe/hiki\_thorの具体的な記述は次の通りである.
|
218
|
+
\begin{lstlisting}[style=customRuby,basicstyle={\scriptsize\ttfamily}]
|
219
|
+
#!/usr/bin/env ruby
|
220
|
+
|
221
|
+
require "hikiutils_thor"
|
222
|
+
|
223
|
+
Hikithor::CLI.start(ARGV)
|
224
|
+
\end{lstlisting}
|
225
|
+
hikiutilsのoptparseバージョンと同様に「require "hikituils\_thor"」ではlib/hikiutils\_thor.rbを読み出してくることを期待している.
|
226
|
+
ここでもgemspecファイルでlibへのロードパスの記述がされているため,hikiutils\_thor.rbを参照することができる.
|
227
|
+
「Hikithor::CLI.start(ARGV)」ではlib/hikiutils\_thor.rbのHikithorモジュールCommandクラスを実行する記述が成されている.
|
228
|
+
|
229
|
+
呼び出される側のlib/hikiutils\_thor.rbの具体的な記述は次の通りである.
|
230
|
+
\begin{lstlisting}[style=customRuby,basicstyle={\scriptsize\ttfamily}]
|
231
|
+
|
232
|
+
module Hikithor
|
233
|
+
|
234
|
+
DATA_FILE=File.join(ENV['HOME'],'.hikirc')
|
235
|
+
attr_accessor :src, :target, :editor_command, :browser, :data_name, :l_dir
|
236
|
+
|
237
|
+
class CLI < Thor
|
238
|
+
def initialize(*args)
|
239
|
+
super
|
240
|
+
@data_name=['nick_name','local_dir','local_uri','global_dir','global_uri']
|
241
|
+
data_path = File.join(ENV['HOME'], '.hikirc')
|
242
|
+
DataFiles.prepare(data_path)
|
243
|
+
...以下略...
|
244
|
+
\end{lstlisting}
|
245
|
+
通常のclass呼び出しで生成されるようになっている.
|
246
|
+
rubyにおいても通常のclassからの実行では,newした後にexeする.
|
247
|
+
しかし,Thorにおいてはstartという関数名で初期化・実行される.
|
248
|
+
これは,rubyに付属しているRakefileの実行方法とよく似た構文となっている.
|
249
|
+
|
@@ -0,0 +1,234 @@
|
|
1
|
+
{{toc}}
|
2
|
+
!方法
|
3
|
+
!!optparseとthorの比較
|
4
|
+
今回の研究対象のhikiutilsは,optparseというコマンドライン解析ライブラリで実装されている.
|
5
|
+
本研究ではこの代替ライブラリとしてThorの採用を検討した.
|
6
|
+
本章の最初では,FizzBuzzという簡単なコードを例にoptparseとThorにより作成するコマンドライン解析コードの比較を行う.FizzBuzzはThorの使い方を解説した記事{{cite(1-2)}}で紹介されている.比較しやすくするためoptparseでFizzBuzzを新たに実装した.
|
7
|
+
|
8
|
+
!!!Thor
|
9
|
+
Thorとは,コマンドラインツールの作成を支援するライブラリのことである.gitやbundlerのようにサブコマンドを含むコマンドラインツールを簡単に作成することができる{{cite(1-2)}}.
|
10
|
+
|
11
|
+
Thorの基本的な流れとしては
|
12
|
+
#Thorを継承したクラスのメソッドがコマンドになる
|
13
|
+
#クラス.start(ARGV)でコマンドラインの処理をスタートする
|
14
|
+
である{{cite(1-2)}}.
|
15
|
+
|
16
|
+
startに渡す引数が空の場合,Thorはクラスのヘルプリストを出力する.また,Thorはサブコマンドやサブサブコマンドも容易に作ることができる.
|
17
|
+
|
18
|
+
以下に示したコードがThorで記述されたfizzbuzzである.
|
19
|
+
|
20
|
+
<<< ruby
|
21
|
+
module Fizzbuzz
|
22
|
+
class CLI < Thor
|
23
|
+
|
24
|
+
desc 'fizzbuzz', 'Get fizzbuzz result from limit number'
|
25
|
+
def fizzbuzz(limit)
|
26
|
+
print Fizzbuzz.fizzbuzz(limit).join(',')
|
27
|
+
exit
|
28
|
+
end
|
29
|
+
|
30
|
+
desc 'version', 'version'
|
31
|
+
def version
|
32
|
+
puts Fizzbuzz::VERSION
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
>>>
|
37
|
+
|
38
|
+
このコードもoptparseのfizzbuzzと同様fizzbuzzとversionのコマンドを実行させる.
|
39
|
+
!!!!fizzbuzzメソッド,versionメソッド
|
40
|
+
descでコマンド一覧で表示させるコマンド名と説明を書く.メソッド内ではそれぞれのコマンドの処理内容が書かれている.
|
41
|
+
|
42
|
+
!!!optparse
|
43
|
+
optparseとは,getoptよりも簡便で,柔軟性に富み,かつ強力なコマンドライン解析ライブラリである.optparseでは,より宣言的なスタイルのコマンドライン解析手法,すなわちOptionParserのインスタンスでコマンドラインを解析するという手法をとっている.これを使うと,GNU/POSIX構文でオプションを指定できるだけでなく,使用法やヘルプメッセージの生成も行える{{cite(1-3)}}.利用頻度はあまり高くないが古くから開発され,使用例が広く紹介されている.
|
44
|
+
|
45
|
+
optparseの基本的な流れとしては
|
46
|
+
#OptionParserオブジェクトoptを生成する
|
47
|
+
#オプションを取り扱うブロックをopt.onに登録する
|
48
|
+
#opt.parse(ARGV)でコマンドラインを実際にparseする
|
49
|
+
である.
|
50
|
+
|
51
|
+
OptionParserはコマンドラインのオプション取り扱うためのクラスであるためオブジェクトoptを生成されopt.onにコマンドを登録することができる.しかし,OptionParser\#onにはコマンドが登録されているだけであるため,OptionParser\#parseが呼ばれた時,コマンドラインにオプションが指定されていれば実行される.optparseにはデフォルトとして--helpと--versionオプションを認識する{{cite(1-4)}}.
|
52
|
+
|
53
|
+
以下に示したコードがoptparseで記述したfizzbuzzである.
|
54
|
+
|
55
|
+
<<< ruby
|
56
|
+
module Fizzbuzz
|
57
|
+
class Command
|
58
|
+
|
59
|
+
def self.run(argv)
|
60
|
+
new(argv).execute
|
61
|
+
end
|
62
|
+
|
63
|
+
def initialize(argv)
|
64
|
+
@argv = argv
|
65
|
+
end
|
66
|
+
|
67
|
+
def execute
|
68
|
+
options = Options.parse!(@argv)
|
69
|
+
sub_command = options.delete(:command)
|
70
|
+
case sub_command
|
71
|
+
when 'fizzbuzz'
|
72
|
+
fizzbuzz(options[:id])
|
73
|
+
when 'version'
|
74
|
+
version
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
def fizzbuzz(limit_number)
|
79
|
+
(0..limit_number).map do |num|
|
80
|
+
if (num % 15).zero? then print 'FizzBuzz'
|
81
|
+
elsif (num % 5).zero? then print 'Buzz'
|
82
|
+
elsif (num % 3).zero? then print 'Fizz'
|
83
|
+
else print num.to_s
|
84
|
+
end
|
85
|
+
print ' '
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
89
|
+
def version
|
90
|
+
puts Fizzbuzz::VERSION
|
91
|
+
exit
|
92
|
+
end
|
93
|
+
end
|
94
|
+
end
|
95
|
+
>>>
|
96
|
+
|
97
|
+
このコードはfizzbuzzとversionをコマンドとして実行できる.
|
98
|
+
!!!!runメソッド
|
99
|
+
コマンド実行を行うためのメソッドであり,argv配列を代入することでexecuteメソッドを実行する.
|
100
|
+
!!!!initializeメソッド
|
101
|
+
初期化を行うメソッドである.
|
102
|
+
<<<
|
103
|
+
@argv = argv
|
104
|
+
>>>
|
105
|
+
こうすることでargvをクラス内で利用できるようにする.
|
106
|
+
!!!!executeメソッド
|
107
|
+
上記でoptparseではopt.onにコマンドを登録する必要があると説明したが,opt.onで登録できるものはハイフンがついたコマンドだけであり,ハイフンなしのコマンドの登録はこのようになる.
|
108
|
+
|
109
|
+
argv配列の解析を行うOptions.parse!(@argv)をoptionsに代入して解析を行いsub_commandに代入する.sub_commandがfizzbuzzであればfizzbuzz(options[:id])メソッドを実行,versionであればversionメソッドを実行する.
|
110
|
+
!!!!fizzbuzzメソッド
|
111
|
+
引数としてlimit_numberを受け取り,0〜limit_numberまでの数字を繰り返す.numが15であればFizzbuzzを表示,5であればBuzzを表示,3であればFizzを表示,それ以外は数字を表示し,その後に空白を表示する.
|
112
|
+
!!!!versionメソッド
|
113
|
+
fizzbuzzのバージョンを表示する.
|
114
|
+
|
115
|
+
|
116
|
+
!!既存のhikiutilsのコマンド解説
|
117
|
+
既存のhikiutilsはコマンド解析ライブラリのoptparseを用いて,コマンドの処理を行っている.
|
118
|
+
optparseの特徴は,「コマンドの登録,実行method」に分けて記述することが期待されている.
|
119
|
+
また,CLIの起動の仕方が特徴的である.この二つを取り出して,動作とコードを説明する.
|
120
|
+
|
121
|
+
!!!コマンドの登録と実行メソッド
|
122
|
+
|
123
|
+
!!!!caption:(fig:005)コマンドの登録と実行メソッドの対応.
|
124
|
+
{{attach_view(hikiutils_yamane.005.jpg,hikiutils_yamane)}}
|
125
|
+
|
126
|
+
optparseでは以下の通り,コマンドの登録と実行が行われる.
|
127
|
+
#OptionParserオブジェクトoptを生成
|
128
|
+
#optにコマンドを登録
|
129
|
+
#入力されたコマンドの処理のメソッドへ移動
|
130
|
+
optparseではOptionParserオブジェクトoptの生成を行い,コマンドをoptに登録することでコマンドを作成することができる.しかし,これはコマンドを登録しているだけでコマンドの一覧ではこれを表示することができるが,コマンドの実行を行うためには実行を行うためのメソッドを作成する必要がある.optparseでのコマンドの実行はoptで登録されたコマンドが入力されることでそれぞれのコマンドの処理を行うメソッドに移動し処理を行う.しかし,このコマンド登録はハイフンを付けたコマンドしか登録ができず,ハイフンなしのコマンド登録はまた別の手段でやらなくてはいけない.
|
131
|
+
|
132
|
+
<<< ruby
|
133
|
+
def execute
|
134
|
+
@argv << '--help' if @argv.size==0
|
135
|
+
command_parser = OptionParser.new do |opt|
|
136
|
+
opt.on('-v', '--version','show program Version.') { |v|
|
137
|
+
opt.version = HikiUtils::VERSION
|
138
|
+
puts opt.ver
|
139
|
+
}
|
140
|
+
opt.on('-s', '--show','show sources') {show_sources}
|
141
|
+
opt.on('-a', '--add','add sources info') {add_sources }
|
142
|
+
opt.on('-t', '--target VAL','set target id') {|val| set_target(val)}
|
143
|
+
opt.on('-e', '--edit FILE','open file') {|file| edit_file(file) }
|
144
|
+
|
145
|
+
...省略...
|
146
|
+
|
147
|
+
end
|
148
|
+
begin
|
149
|
+
command_parser.parse!(@argv)
|
150
|
+
rescue=> eval
|
151
|
+
p eval
|
152
|
+
end
|
153
|
+
dump_sources
|
154
|
+
exit
|
155
|
+
end
|
156
|
+
|
157
|
+
def show_sources()
|
158
|
+
printf("target_no:%i\n",@src[:target])
|
159
|
+
printf("editor_command:%s\n",@src[:editor_command])
|
160
|
+
|
161
|
+
...省略...
|
162
|
+
|
163
|
+
end
|
164
|
+
|
165
|
+
以下略
|
166
|
+
|
167
|
+
>>>
|
168
|
+
|
169
|
+
!!!CLIの実行プロセス
|
170
|
+
!!!!caption:(fig:007)CLIの実行プロセス.
|
171
|
+
{{attach_view(hikiutils_yamane.007.jpg,hikiutils_yamane)}}
|
172
|
+
|
173
|
+
optparseを用いた場合のCLIの実行プロセスは次の通りとなる.
|
174
|
+
#HikiのHikiUtils::Command.run(ARGV)でhikiutils.rbのrunメソッドを呼ぶ
|
175
|
+
#new(argv).executeでexecuteメソッドが実行される
|
176
|
+
|
177
|
+
optparseではHikiutils::Command.run(ARGV)で実行され,requireで呼び出されたhikiutils.rbのrunメソッドが実行される.そこでコマンドを登録しているexecuteメソッドへ移動し入力したコマンドと対応させる.そして,対応したコマンドの処理が行われるメソッドに移動することで実行される.このようにoptparseでは実行を行うためのメソッドが必要である.
|
178
|
+
!!!コード
|
179
|
+
|
180
|
+
optparseの呼び出し側のexe/hikiのコードは次の通りである.
|
181
|
+
<<< ruby
|
182
|
+
#!/usr/bin/env ruby
|
183
|
+
|
184
|
+
require "hikiutils"
|
185
|
+
|
186
|
+
HikiUtils::Command.run(ARGV)
|
187
|
+
>>>
|
188
|
+
「require "hikituils"」ではlib/hikiutils.rbを読み出してくることを期待している.
|
189
|
+
これはgemspecファイルでlibへのロードパスの記述がされているため,hikiutils.rbを参照することができる.
|
190
|
+
「Hikiuils::Command.run(ARGV)」ではlib/hikiutils.rbのHikiUtilsモジュールCommandクラスのrunメソッドを実行する記述が成されている.
|
191
|
+
|
192
|
+
|
193
|
+
また呼び出される側のlib/hikiutils.rbのrunおよびexecute部のコードは次の通りとなる.
|
194
|
+
<<< ruby
|
195
|
+
def self.run(argv=[])
|
196
|
+
print "hikiutils: provide utilities for helping hiki editing.\n"
|
197
|
+
new(argv).execute
|
198
|
+
end
|
199
|
+
|
200
|
+
def execute
|
201
|
+
@argv << '--help' if @argv.size==0
|
202
|
+
command_parser = OptionParser.new do |opt|
|
203
|
+
opt.on('-v', '--version','show program Version.') { |v|
|
204
|
+
opt.version = HikiUtils::VERSION
|
205
|
+
puts opt.ver
|
206
|
+
}
|
207
|
+
opt.on('-s', '--show','show sources') {show_sources}
|
208
|
+
opt.on('-a', '--add','add sources info') {add_sources }
|
209
|
+
opt.on('-t', '--target VAL','set target id') {|val| set_target(val) }
|
210
|
+
opt.on('-e', '--edit FILE','open file') {|file| edit_file(file) }
|
211
|
+
opt.on('-l', '--list [FILE]','list files') {|file| list_files(file) }
|
212
|
+
opt.on('-u', '--update FILE','update file') {|file| update_file(file) }
|
213
|
+
opt.on('-r', '--rsync','rsync files') {rsync_files}
|
214
|
+
opt.on('--database FILE','read database file') {|file| db_file(file)}
|
215
|
+
opt.on('--display FILE','display converted hikifile') {|file| display(f\
|
216
|
+
ile)}
|
217
|
+
opt.on('-c', '--checkdb','check database file') {check_db}
|
218
|
+
opt.on('--remove FILE','remove file') {|file| remove_file(file)}
|
219
|
+
opt.on('--move FILES','move file1,file2',Array) {|files| move_file(file\
|
220
|
+
s)}
|
221
|
+
opt.on('--euc FILE','translate file to euc') {|file| euc_file(file) }
|
222
|
+
opt.on('--initialize','initialize source directory') {dir_init() }
|
223
|
+
end
|
224
|
+
begin
|
225
|
+
command_parser.parse!(@argv)
|
226
|
+
rescue=> eval
|
227
|
+
p eval
|
228
|
+
end
|
229
|
+
dump_sources
|
230
|
+
exit
|
231
|
+
end
|
232
|
+
>>>
|
233
|
+
runメソッドでは「hikiutils: provide utilities for helping hiki editing.」を表示させ,executeメソッドを実行させる.
|
234
|
+
executeメソッドでは最初に「@argv << '--help' if @argv.size==0」と記述する.これはもしargv配列の中身が空であればargv配列に'--help'を代入する.「command_parser = OptionParser.new do |opt|」ではOptionParserオブジェクトがoptを生成しコマンドを登録していき,command_parserに代入する.そして,「command_parser.parse!(@argv)」では@argvにある文字列をcommand_parserでparseする.つまり,ここでは入力されたコマンドを解析し,登録されたコマンドと一致すればその処理が行われる.もし,一致しなければevalメソッドで表示する.
|