「ネオ写経」のすすめ

「ネオ写経」のすすめ

新型コロナウイルス対応で外出の自粛が求められる中、みなさまいかがお過ごしでしょうか。

ろくにテレワーク環境も整っていないのに、「とにかくテレワークだ!」的に導入されてしまった事業所も、それなりにあると思います。

個人的には、この期間は〈終息後のダメージ回復〉を効果的に行うために個人が力量を高める機会ととらえるのが良いと思います。それができる余裕のある業界に限られますが……。

「ネオ写経」とは

私が勝手に考えました。

もともと、プログラミング界隈で「写経」といえば、サンプル・コードの類を写すこと。(ですよね?)

ただ、私は「写経」というものをしたことがほぼない。写しているうちに、「あら? じゃあ、ここはこうした方がおもろいやんけ。」とか、「ついでにこうしといたれ。」みたいなのが出てくるから、「般若心経」を写していたはずなのに、なぜか「あほだら経」が出来上がっていた、ということが起こる。

そんな私が考えた「ネオ写経」とは!?

既存クラスをラップしたクラスを作る。

これ。

ニセFileSystemObjectを作る

FileSystemObjectは便利だ。

しかも、プロパティ名とかメソッド名は、さすがプロが作っただけあって、実に良くできている。コードが実に読みやすくなる。

ところが、デフォルトでは使えない。

いちいち参照設定をせねばならん。

もちろんCreateObjectを使えば参照設定せずにすむ。

しかし、これだとObject型変数に突っ込んで使用することになり、コーディング時に入力補完の恩恵が得られずイマイチ。

もちろん、コーディング時に参照設定をしておき、完成したら参照設定を切る、という方法もあるにはあるが、それはそれでメンドクサイ。

だったら、FileSystemObjectクラスをラップしたFileSystemObjectクラスを自作しちまえばいいんでねえの!

コンストラク

これは簡単。Class_InitializeScripting.FileSystemObjectクラスのインスタンスを得ればよい。

まず、プロジェクトにクラスモジュールを挿入し、オブジェクト名をFileSystemObjectにする。そして、クラスモジュールに次のコードを書く。

クラスモジュール FileSystemObject
'Declarations Section'
'Module Level Variables'
Private fsObj As Object

'Constructor'
Private Sub Class_Initialize()
  Set fsObj = CreateObject("Scripting.FileSystemObject")
End Sub

これだけ。

これで、プロパティとかメソッドをこの変数fsObjを経由して呼び出すようにすればいい。

プロパティとメソッドの実装(笑)

大袈裟な見出しだが、プロパティをメソッドを実装(笑)するときの教科書が、おれたちの「オブジェクト ブラウザー」様だ!

ブラウザー」と延ばしているところがボスキャラ感があっていいよね。

[F2]キーを押すか何かして、「オブジェクト ブラウザー」を開き、FileSystemObjectを指定すると、

f:id:akashi_keirin:20200425075449j:plain

こんなふうにメンバを確認することができるし、

f:id:akashi_keirin:20200425075453j:plain

こんなふうに各メンバの実装方法を確認することもできる。

あとはコーディングあるのみ!

……である!

プロパティの実装(笑)

……といっても、FileSystemObjectにはプロパティは一つしかない。これは意外だった。なんと、Drivesコレクションを返すDrivesプロパティしかないのだ。

実装方法は、オブブラ(略すなw)によると、

Property Drives As Drives

とのこと。

もちろん、このまま打ち込んでもコンパイルエラーになるので、脳内でコードを補完して

Public Prooerty Get Drives() As Drives

とする。

もちろん、Microsoft Scripting Runtimeを参照設定しないのだから、As Drivesではまずい。で、

Public Prooerty Get Drives() As Object

と、返り値をObject型に改めておく。

あとは中身。

Dim ret As Object
Set ret = fsObj.Drives    '……(1)'
Set Drives = ret    '……(2)'

これでいい。変数fsObjはモノホンのFileSystemObjectクラスのインスタンスを指しているから、そのDrivesプロパティの返り値はもちろんモノホンのDrivesコレクション。

だから、まずは(1)の

Set ret = fsObj.Drives

で返り値用の変数retにモノホンのDrivesコレクションを突っ込んでおき、(3)の

Set Drives = ret

でニセのDrivesプロパティの返り値としてやる。

プロシージャ全体は

Public Prooerty Get Drives() As Object
  Dim ret As Object
  Set ret = fsObj.Drives
  Set Drives = ret
End Property

こう。

メソッドの実装(笑)

メソッドも基本的にはこの方法。

f:id:akashi_keirin:20200425075456j:plain

このように、オブブラ(笑)で、

  • SubFunctionの別
  • 引数リスト
  • 引数がOptionalかどうか
  • 返り値の型

を確認し、それに応じてコーディングすればいい。

たとえば先の画像のCreateTextFileメソッドならば、

  • 種別はFunction
  • 引数はFileNameOverWriteUnicodeの三つ。
  • 引数OverWriteUnicodeOptional
  • 返り値はTextStream

なので、それに応じてコーディングする。

Public Function CreateTextFile( _
	    ByVal FileName As String, _
   Optional ByVal OverWrite As Boolean = True, _
   Optional ByVal Unicode As Boolean = False) As TextStream

となる。

しかし、TextStreamクラスもScripting.FileSystemObjectクラスのメンバなので、Objectにする。

Public Function CreateTextFile( _
	    ByVal FileName As String, _
   Optional ByVal OverWrite As Boolean = True, _
   Optional ByVal Unicode As Boolean = False) As Object

こうなる。

プロシージャ全体は

Public Function CreateTextFile( _
	    ByVal FileName As String, _
   Optional ByVal OverWrite As Boolean = True, _
   Optional ByVal Unicode As Boolean = False) As Object
  Dim ret As Object
  Set ret = fsObj.CreateTextFile(FileName, OverWrite, Unicode)
  Set CreateTextFile = ret
End Function

こう。

引数が列挙体型のやつがある

あと、メソッドの中には引数がScripting.FileSystemObjectの中で定義された列挙体であるものがある。

たとえば、

f:id:akashi_keirin:20200425075458j:plain

このGetStandardStreamメソッドの場合、

Function GetStandardStream(StandardStreamType As StandardStreamTypes, [Unicode As Boolean = False]) As TextStream

とあるように、第1引数StandardStreamTypeStandardStreamTypesという見慣れない型である。

こいつは、オブブラ(笑)で見ると

f:id:akashi_keirin:20200425075501j:plain

となっているように、Scriptingクラスで定義された列挙体なんである。

当然、Microsoft Scripting Runtimeを参照設定していないと使えない。

そういうときはどうするか。

このニセFileSystemObjectクラスモジュール内でPublic Enumにしてしまえばいいのである!

'Declarations Section'
'Constants'
Public Enum StandardStreamTypes
  StdIn = 0
  StdOut = 1
  StdErr = 2
End Enum

列挙体のメンバがそれぞれどの数値を表しているのか、というのもオブブラ(笑)先輩を見ればわかる。

f:id:akashi_keirin:20200425075504j:plain

ほれ。こんなふうに。

Scripting.__MIDL___MIDL_itf_scrrun_0001_0001_0003ちゅうのは何のことやらわからんがw

おわりに

上記のようにして、ひたすらプロパティ・メソッドを実装(笑)し続けることを、「ネオ写経」と呼んでおります。

オブジェクトの仕組みがよくわかって実に勉強になります。

「新型コロナ自粛で勉強ぐらいしかすることがない」という人は、一度やってみてはいかがでしょうか?

ちなみに、FileSystemObjectは、配下にDrivesDriveFoldersFolderFilesFileTextStreamというScripting内のオブジェクトを抱えているので、本気でFileSystemObjectクラスを丸ごとラップしようと思ったら、全部で八つもクラスモジュールを作ることになりますw

f:id:akashi_keirin:20200425075507j:plain

こんなふうに。

特に、Folders-Folderのような階層構造を持つクラスを表現するのにめちゃくちゃ頭を使いましたw