Blank?=False

ゆるゆる仕事したいフリーランスエンジニアの記事

VBAでRedisに接続 その3 [完結編]

f:id:stonebeach-dakar:20161204184825p:plain

何回目かのVBAでRedisを使うポストですが、ようやく今回で無事VBAからのRedisアクセスができるようになりました。

C#VBAのDLLを作成する方法

VBAから他の言語で書かれたDLLを作成する場合、2パターンあります。

  • COMインターフェースを持つDLLを環境設定で追加して使用する。
  • 通常のDLLをDllImportして使用する。


今回は勉強がてらCOMインターフェースを持つDLLを作成します。
COMインターフェースで作れば、インテリセンスも効くしヒントも表示されるので使いやすくなります。


COMインターフェースとは

COMインターフェースCOMインターフェースと言っていますがそもそもCOMインターフェースって何?
なところがあったので調べてみました。

Component Object Modelとは、マイクロソフトが提唱するソフトウェアの再利用を目的とした技術のことである。
アプリケーションソフトウェア間の通信や、OSとアプリケーションソフトウェアとのAPIに用いられる。
Component Object Model - Wikipedia


主にWindowsで使われるライブラリの基盤的なもの、という感じかな。
現在は殆どが.Net Frameworkに移行しているけど、C++では現役バリバリ、だそうだ。

VBAはそもそもが.Net以前のVBをベースにした言語なので、COMとは相性が良いんでしょう。

StackExchange.RedisにCOM設定を入れてビルドする

早速、StackExchange.Redisの設定でCOM参照を追加…等やってみてビルドします。
f:id:stonebeach-dakar:20161219210825p:plain



そうは問屋がおろしまへんで!とばかりにビルドエラーが発生しました。
f:id:stonebeach-dakar:20161219210740p:plain

ビルドエラーの原因

ビルドエラー内容を見ると、ジェネリック型はCOMインターフェースで使えないようです。
このジェネリック型、ですがC#Javaにある機能で、型が違うけど同じような処理を実装する時にに使えるものです。
C++には似たようなテンプレートと言う機能があります。
動的型付け言語のRubyでは特にこういった機能はなかった気がします。

別dllファイルとしてラッパーdllを作成する

ジェネリック型を含むコードをビルドしてdllを作成する場合、COMインターフェースの実装ができないので、ジェネリック型を使わない COMインターフェース用のラッパーDLLを作成してVBAからはそのラッパーDLLを経由したアクセスを行う方針で作成することにしました。

NugetでStackExchange.Redisをインストール

VisualStudioには、RubyのGemとかMacのHomeBrewのようなNugetというパッケージマネージャーがあり、それで開発環境にStackExchange.Redisを含めることが出来ます。
実はVisualStudio4年使っていて初めてVisualStudioにもNugetがあることを知りました
StackExchange.RedisのReadmeにある通りNugetのパッケージマネージャーコンソールを開いて、以下を入力します。

PM> Install-Package StackExchange.Redis



これで環境へStackExchange.Redisが準備できるので、プロジェクトのプロパティでCOM関係の設定をした後、COMインターフェースと空のクラスを作って、COM公開用の属性などを追加してビルドします。

よっしゃこれでよかろ!とおもったらビルドエラー。
なんでや!?と思ってエラーメッセージを見ると、レジストリにアクセス出来ませんでした…とあります。
f:id:stonebeach-dakar:20161219211319p:plain
COMインターフェースアセンブリを登録するためにはレジストリに登録する必要があるようで、 一般ユーザ権限でVisualStudioを起動しているときのビルドだと、レジストリに登録する権限がないので正常にCOMインターフェースが登録出来ない、ということみたいですね。


というわけで、VisualStudioを管理者モードとして起動してビルドすることで正常にビルドが通りました。

とりあえず基本的な読み書きだけやってみる

前回作成したBasicUsageを見ると、ConnectionMultiplexerクラスのConnect,GetDatabase、そしてIDatabaseインターフェースのStringGet,StringSetがあれば基本的な読み書きはできそうです。
というわけで、2つのクラスのCOMインターフェースとラッパークラスを作成したものをビルドします。

ConnectionMultiPlexer.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Runtime.InteropServices;
using System.ComponentModel;
using StackExchange.Redis;


namespace StackExchange.Redis_COM
{
    [ComVisible(true)]
    public interface IConnectionMultiplexer
    {
        [Description("Create a new ConnectionMultiplexer instance")]
        ConnectionMultiplexer Connect(string configuration);

        [Description("Obtain an interactive connection to a database inside redis")]
        Database GetDatabase(int db = -1);
    }

    [ComVisible(true)]
    [ClassInterface(ClassInterfaceType.None)]
    public class ConnectionMultiplexer : IConnectionMultiplexer
    {
        private Redis.ConnectionMultiplexer ConnectionMultiplexerInstance;

        public ConnectionMultiplexer Connect(string configuration)
        {
            ConnectionMultiplexerInstance = Redis.ConnectionMultiplexer.Connect(configuration);
            return this;
         }

        public Database GetDatabase(int db = -1)
        {
            return new Database(ConnectionMultiplexerInstance.GetDatabase(db));
        }
    }
}


Database.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Runtime.InteropServices;

namespace StackExchange.Redis_COM
{
    [ComVisible(true)]
    public interface IDatabase
    {
        void StringSet(string key, string value);
        string StringGet(string key);
    }

    [ComVisible(true)]
    [ClassInterface(ClassInterfaceType.None)]
    public class Database : IDatabase
    {
        private Redis.IDatabase IDatabaseInstance;

        public Database(Redis.IDatabase IDatabase)
        {
            IDatabaseInstance = IDatabase;
        }

        public void StringSet(string key, string value)
        {
            IDatabaseInstance.StringSet(key, value);
        }

        public string StringGet(string key)
        {
            return IDatabaseInstance.StringGet(key);
        }
    }
}

VBAで使ってみる

作成したCOMインターフェースをVBEの環境設定で使う用に設定して、BasicUsageをVBAで書いてみます。
f:id:stonebeach-dakar:20161219212027p:plainf:id:stonebeach-dakar:20161219212038p:plain

Option Explicit
Public Sub Redis_BasicUsage()
    Dim Connection_Dummy As New Redis_COM.ConnectionMultiplexer
    
    Dim Connection As Redis_COM.ConnectionMultiplexer
    Set Connection = Connection_Dummy.Connect("localhost")
    
    Dim Redis As Redis_COM.Database
    Set Redis = Connection.GetDatabase
    
    Redis.StringSet "mykey", "foo"
    Debug.Print Redis.StringGet("mykey")
End Sub

実行結果
f:id:stonebeach-dakar:20161219210709p:plain


結果、無事Redisにアクセスしてデータを設定、取得ができました。

あとがき

今回作成したRedisのCOMインターフェースはGitHubに上げました。
github.com
examplesディレクトリにVBAでの使用例を保存してあります。


せっかくなのでC#を勉強がてら、実用的なレベルまで作成した後、Redisのクライアント一覧に登録までやっちゃおうかなと思います。

応用情報技術者試験に合格しました&勉強方法振り返り

先日、とうとう平成28年度秋季情報技術者試験の合格発表があり、
無事応用情報技術者試験に合格できました。

結果としては↓みたいな感じです。
f:id:stonebeach-dakar:20161217124806p:plain

以前、↓のような記事を書いたのですが stonebeach-dakar.hatenablog.com

あらためて勉強方法をまとめなおしてみました。

続きを読む

私、Atomを卒業します。普通のVim使いになります!

f:id:stonebeach-dakar:20161210103249p:plain

私、Atomを卒業します。
普通の女の子になります!
普通のVim使いになります!

いや、真面目に、Atomを卒業します。

なんでかというと、「達人プログラマー」で2つのエディタを使っているような状況は良くないよ、 という話があったんです。

達人プログラマーに書いてあったこと

いくつか抜き出します。

1つのエディタを知り尽くしておき、コーディング、ドキュメント作成、メモ、システム管理といった編集作業は、全てそれを使用して行うことをお勧めします。
複数種類のエディタの使用によって、現代におけるバベルの塔の混乱に直面する可能性があるのです。
異なった編集規約やコマンドが個別にそんざいすると、それぞれの環境への熟達が難しいものとなってしますのです。
あなたは一芸に秀でている必要があります。
強力なエディタとあなたの指先を使えば、高い生産性を上げられるようになります。

もし1つのエディタをすべてのテキスト編集作業で使えるのであれば、テキスト操作のたびに立ち止まって考え込む必要もなくなり、反射的にキー入力が行えるようになります。
エディタは手の延長となり、軽やかなキー入力の音はテキストと指向の間を抜ける小道を渡る小鳥のさえずりのようになるのです。それが目標です。

達人プログラマー 第3章 パワーエディットより

新装版 達人プログラマー 職人から名匠への道

新装版 達人プログラマー 職人から名匠への道

エディタはどんな操作をする時でも1種類だけにしてしまおう!という考え方です。
ただ、IDEに依存する言語(VBADelphi等)もあるので、そういった言語は除いていいと思います。

この考え方ですが、最近はMicrosoftもVSCode等でどのような言語でも使えるエディタをだしてきたりと、昨今のトレンドになっている気がします。

今まで使っていたエディタについて

AtomVim。どちらもオープンソースのエディタです。
ターミナルからの開発はVim,デスクトップからはAtomの2本体勢を2年ぐらいやっていました。
プラグインを入れればお互いのキーバインドも近づけるのは知っていたんですが、余り気にしていなかったので両方のキーバインドを覚えるという効率が悪いことをやっていました。
そのせいで何方か一方しか使わない時期があるとすぐにキーバインドを混乱して使ってしまうこともありました。

なぜAtomを使っていたのか

まだCUIベースのVimに慣れていない時に出てきた新しいエディタで、色々なパッケージをつかうことで様々な言語に対応出来る!などの触れ込みが気になって使い始めました。
実際、当初は使いやすく色々な開発をこのAtomでやっていたのですが、最近はよくクラッシュするためもっぱらMarkDownCSS、HTML専用エディタになっていました。

なぜVimを使っていたのか

最初、Vimを使い始めた理由は尊敬するプログラマの1人である@junichi_itoさんが紹介していたのがきっかけです。
@junichi_itoさんはもうVimをやめてRubyMineに移行したみたいですが


blog.jnito.com

最初さわった時は何だこの使いにくいエディタは!?と思っていたのですが、 慣れてくると非常にテンポよくタイプできるので、もう手放せないエディタとなりました。

また、設定ファイルのVimrcをGitHubなどにアップしておけば家で使っている環境をそのまま会社のPCでも使える、というのがお気に入りでした。
そして、Rubyを書くとターミナルで動作確認をすることが多いので、キーボードから手を離すことなく動作確認が行えるため、Rubyの開発では重宝します。

ただ、プラグインを入れていないだけなのにいろんな理由をつけては余り使わなかった時期があり、その間にAtomを使っていた感じです。
最近、Vimを使う機会が増えたおかげで改めてVimのほうが使いやすいな!と気づきました。

なぜAtomをやめるのか

なんかね、よくクラッシュするんですよ。
自分の環境だけかもしれませんが。

そして、クラッシュするとプロジェクトフォルダや開いていたタブが全部消えるので、また設定して、開き直して…というのがめんどくさくなってきました。

そしてもう1つ、設定を様々なOSで共有できない、Rubyを書いているとターミナルで動きを確認、というのが多いんですね。
なので、Term3などのターミナルパッケージを使っていたんですが、Atomのターミナルってどれもイマイチな出来で、結局Atomとターミナルを同時起動して入力が終わったらマウスを持ってターミナルにフォーカスを当ててまたキーボードで入力・・・というプロセスを踏む必要があったんです。
これがまた面倒臭い。集中しているときはなかなかキーボードから手を離したくないんですよね。

ということで、ちゃんとしたターミナルが使える環境の上で動作するVimのほうがベストでは?と思いました。

Atomから完全にVimに移行するためにやったこと

ここから、Atomを完全にやめて完全なVimmerとなるためにやったことを書いていきます。

Atomをアンインストール

潔く消してしまいましょう。自らを背水の陣に追い込むのです!

Vimの操作を完全に覚える

Vimをそこそこ使っていたものの、基本的な操作を完全に覚えているわけではありませんでした。
これを機会にちゃんと覚えないと、と思いました。

これはVimチュートリアルが便利です。3回ぐらいで大分なれてきたかな、という感じでした。
ちなみに30分で終わる、と言われているのですが自分の場合、初回は1時間ぐらいかかっていたような気がします。

nanasi.jp

Atomを使っていた理由をなくす

AtomVimを使い分けていた理由をなくしてしまえば

「こういうことがAtomで出来ていたのにVimはできない。やっぱAtom必要だ。」

なんてことがなくなります。

Vimは長い間世界中の人に愛されたエディタなのでそのプラグインの数はAtomよりずっと多くあり、他のエディタにあってVimにないプラグインはない、とまで言われています。

VimMarkDownのプレビュー表示に対応する

AtomではMarkDownPreviewというプラグインでプレビュー表示をしつつMarkdownテキストをガリガリ書ける機能を付けていました。
f:id:stonebeach-dakar:20161210105900p:plain

これでブログなりQiita記事なりを書いていたのですが、これはターミナルで動くVimじゃ無理だろなー、と思っていたのですが、 調べてみたらやりようがあったと知って決めつけちゃっていたな〜と反省。


下のサイトとリポジトリのReadMeを参考に設定するだけでOKでした。これでVimでブログ記事が書ける!
実際に使ってみても非常に便利です。リアルタイムじゃないけど、リアルタイムプレビューはたいてい重くなりやすいので保存時のプレビュー反映のほうが使いやすい気がします。

VimでMarkdownの環境を整える | KEYPOINT – キー・ポイント株式会社 開発日誌


というわけでこの記事は、こんな感じでブラウザでプレビューしながらVimでガリガリ書きました。
f:id:stonebeach-dakar:20161210105710p:plain

RGB値からカラーのプレビュー表示できるようにする

Atomでは、プラグインを入れることでCSSなどに書かれた色設定のプレビューが表示される、等の機能がありました。

f:id:stonebeach-dakar:20161210103521p:plain
これはVimだと無理だろ〜なんて思ってましたがありました。
Vimすげぇ。
f:id:stonebeach-dakar:20161210103543p:plain
blog.scimpr.com


これから

今使っているvimrcは元々まだまだVimに慣れていない頃、ネットで紹介されたオススメ設定とかプラグインをどんどん入れていったものなので、ちょっとメチャクチャなところがあったり、使っていないプラグインがあったります。
完全にVimに移行したので、vimrcファイルをそのうち整理してより使いやすくしていきたいな〜と思います。
とりあえずVim本を買ってみたので読みながらよりVimを使いこなせるようやってきます。



え?Emacs?やだなぁ使いませんよ?
学生時代はEmacs使っていた人

RedisをWindowsにインストールしてVBAで使ってみようとした話

f:id:stonebeach-dakar:20161204184825p:plain RedisというNoSQLデータストアがちょっぱや!な噂をどっかから聞いてみて、興味をもったので ちょっくらつかってみっか、ついでにVBAで使えんかなという感じでRedisに触ってみました。

続きを読む

クロージャを学ぶ その心は?

とある事を以前、職場の上司に言われた。

プログラマを何年もやっていてもわからないことは多い。
実は基本的なこともしらなかったこともあるしよくわかってなかった、と言うのは本当によくある。
大切なのはよくわからないまま放置しないことだ。


はい、わからないまま放置していること多いです!

というわけで、今回はよくわからない基本的なことの1つ、クロージャをお勉強。

クロージャって何?

Wiki先生に聞きましょう。

クロージャクロージャー、英語: closure)、関数閉包はプログラミング言語における関数オブジェクトの一種。
いくつかの言語ではラムダ式や無名関数で実現している。
引数以外の変数を実行時の環境ではなく、自身が定義された環境(静的スコープ)において解決することを特徴とする。関数とそれを評価する環境のペアであるともいえる。 主な利点としてはグローバル変数の削減が挙げられる。
クロージャ - Wikipedia

ちょっとよくわかりません。日本語でry
色々なサイトで勉強してみて、ようやく意味がつかめました。

下の2点がクロージャの特徴です。

引数以外の変数を実行時の環境ではなく、自身が定義された環境で(以下略)

これは、関数そのものをオブジェクトとして持って、引数以外の変数は前回実行時の状態を保存しておく、
ということです。

主な利点としてはグローバル変数の削減が挙げられる

上の前回その関数を実行した状態を保存しておく、という利点を使って、
その関数が実行された回数をわざわざグローバルで持たず関数オブジェクトで保持することが可能になります。

自分的には、クロージャとは
関数の状態を保存して、いつでもその状態で処理を始められる方法と解釈しました。

クロージャの実際の例

よくあるカウンタの例です。

#encoding : utf-8

def increase
    n = 0
    -> { n += 5 }
end

3.times { p increase.call }

puts "==========="

increase_proc = increase
3.times { p increase_proc.call }

この例についての解説は、@ITの記事を参照してください。
他のサイトも見たのですが、ここが詳細にかかれてわかりやすくなっています。
http://www.atmarkit.co.jp/ait/articles/1409/29/news035_3.html

自分がよくわからなかったところ

increase_procという関数オブジェクトを使うことで、nが5,10,15となっていくのはわかります。
でも、n=0の部分はなぜ無視されてしまうのか?これがよくわかりませんでした。

ちょっと悩んだ結果、以下のことに気づきました。

increaseメソッドの返り値は->{ n += 5 }、つまりProcクラス

つまり、increase_procはincreaseメソッドの関数オブジェクトと勘違いしてたわけです。
本当は上の通りProcオブジェクトの中身の関数オブジェクトだったということでした。

勘違いした原因

前職ではC++をやっていたのですが、そのC++に関数ポインタと言うものがありました。
この関数ポインタは、下のような感じで使います。

int Sum(int a, int b){
  return a + b;
}

int (func*)(int, int);
func = Sum; 

C++なら関数オブジェクトを使ったほうが良いです
func = Sumの下りが似てたんですね…
この場合、Sumという関数のポインタをfunc変数に保存する、と言う事になります。
なので、Sum関数全部が1つのfunc変数に入ってます。
C++に慣れてる人は気をつけてください!(こんな勘違いするのは自分だけ)

クロージャをどう使っていくか

上の特徴にある通り、グローバル変数を削減したいといったシチュエーションで使えると思います。
ただ、基本的に私はグローバル変数を使わない実装にしているので、使う機会は余りなさそうな。

これに関しては色々なサイトを見たり自分で使ったりして自分なりの使い方を見つけていく必要がありそうです。

参考文献・サイト

qiita.com qiita.com

おまけ

このクロージャメタプログラミングの技法の1つとされています。
RubyRubyたらしめるのはこのメタプログラミング、ともいわれているのでメタプログラミングをしっかり勉強してみたいところです。
さしあたっては以下の本を読むところから始めないと。

メタプログラミングRuby 第2版

メタプログラミングRuby 第2版

岩波書店のISBNコード騒動について考える。

Twitterを見ていたらこんなまとめを見つけた。

togetter.com

ISBNコードといえば、すべての本に付けられる世界共通で一意なコード、という印象だった。
だけど、そのISBNコードを使いまわす出版社があると知って、 データベースのプライマリキーとかにISBNコードは使えないなぁと思った。

この問題について自分が思うことを書いていきます。

続きを読む