NotesgripによるNotesクラスライブラリのチュートリアル

Notesクラスライブラリについて

Notesクラスライブラリは、Notes/Dominoの各要素をクラスの形で抽象化したもの。

Notesの要素クラス名
データベースNotesDatabase
ビューNotesView
文書NotesDocument
フィールドNotesItem
リッチテキストフィールドNotesRichTextItem
添付ファイルNotesEmbeddedObject
ACLNotesACL
ACLの各権限NotesACLEntry
検索結果NoesDocumentCollection
Notes実行環境NotesSession

Notesクラスライブラリ利用の基本

このように、Notesの各要素を指すオブジェクトがほしいなら、その要素が属する親の要素に対して、「xxxをちょうだい」と指示すると、目的の要素のオブジェクトが手に入るようになっている

この指示のことを「メソッド」とか「プロパティ」と呼ぶ。おおまかなくくりでは、「xxxして頂戴」というのが「メソッド」、「xxxを教えて」というのがプロパティと思えばいい。ただ、両者に 本質的な違いはない。

各要素を指すオブジェクトが手に入ったら、どんな指示が出せるか調べる必要がある。それには、Notesのヘルプを見るといい。

DominoOLEHelp

ずらっとNotesクラスが並んでいるので、目的のクラスを開いてみる。そうすると、そのクラスで提供しているプロパティとメソッドの一覧が載っているので、 そのメソッドの機能、引数、戻り値などを調べれる。

例えば、NotesSessionのヘルプのGetDatabase()を見ると、以下のように書いてある。

  GetDatabase メソッド
  例
  指定されたサーバーとファイル名のデータベースを表す NotesDatabase オブジェクトを作成し、
  そのデータベースを開きます。
  
  定義位置
  NotesSession
  構文
  Set notesDatabase = notesSession.GetDatabase( server$, dbfile$ [, createonfail ] )
  

これを読めば、引数にサーバ名とDBファイル名を指定してやればNotesDatabaseを返すメソッドだというのがわかる。

Notesクラスライブラリを使ったプログラミングとは

通常、NotesクラスライブラリはNotesの内部で使用する。 ボタンに書いておけば、ボタンを押した時の処理を記述できるし、フォームのイベントに記述しておけば、文書保存時の処理記述できる。 エージェントに記述しておけば、選択した文書にやや複雑な処理を施すといったこともできる。

OLE/COMインタフェース

WindowsにはCOMとかOLEと呼ばれるインタフェースが用意されていて、Notesの外部からNotesのクラスライブラリを利用できるようになっている。

RubyにはWIN32OLEというライブラリが用意されていて、これを使えばこんな感じでRubyからNotesのクラスライラリを利用できる。

  require 'win32ole'
  
  ns = WIN32OLE.new('Notes.NotesSession')
  db = ns.GetDatabase("technotes", "log.nsf")
  view = db.GetView("MiscEvents")
  doc = view.GetFirstDocument
  while doc
    form_name = doc.GetItemValue('Form')
    events = doc.GetItemValue('EventList')
    puts "Form:#{form_name}, events:#{events}"
    doc = view.GetNextDocument(doc)
  end  
  

変数名やメソッドからわかると思うが、3行目のnsはNotesSession、dbはNotesDatabaseのオブジェクトを指す変数。 しかし、WIN32OLE経由で得られたオブジェクトのクラス名はすべて"WIN32OLE"になってしまう。

Rubyには、"p doc"とかやると、docが指すオブジェクトのクラス名を知ることができるのだが、全部WIN32OLEクラスではちょっとデバッグしにくい。

また、NotesDatabaseにちょっとした便利な独自メソッドを追加しようとしても、全部WIN32OLEクラスでは、それもできない。

Notesgrip

Notesのオブジェクトを包み込むクラスを作ることで、クラス名に関係する問題を解決できる。

NotesDatabaseオブジェクトを指すRubyのオブジェクトにクラス名を問い合わせれば、"NotesDatabase"と答えさせることもできるし、NotesDatabaseクラスに独自メソッドを定義すれば、 すべてのNotesDatabaseオブジェクトでそのメソッドを利用できるようになる。

そのためのライブラリがNotesgripである。

例えば、先ほどのサンプルはNotesgripを使うと、以下のように記述できる。NotesViewにイテレータであるeach_documentメソッドを用意することで、 ビュー内部の文書を順に処理する記述を簡潔に記述できる。doc = view.GetNextDocument(doc)と書くより実にエレガントだとと思わない?

  require 'notesgrip'
  
  ns = Notesgrip::NotesSession.new
  db = ns.GetDatabase("technotes", "log.nsf")
  view = db.GetView("MiscEvents")
  view.each_document {|doc|
    form_name = doc['Form'].text
    events = doc['EventList'].values
    puts "Form:#{form_name}, events:#{events}"
  }
  

Notesgripのサンプル

DBの一覧をなめるスクリプト

サーバ上の全DBのリストを得るには、通常、NotesDbDirectoryを使う。

  ns = Notesgrip::NotesSession.new
  db_directory = ns.GetDbDirectory( "technotes" )
  db = db_directory.GetFirstDatabase
  while db
    p db
    db = db_directory.GetNextDatabase
  end
  

これをNotesgripらしく書くとこうなる。NotesSessionクラスにeach_databaseというメソッドを定義しているおかげ。

  ns = Notesgrip::NotesSession.new
  ns.each_database("technotes") {|db|
    p db
  }
  

DB中の文書をなめるスクリプト

NotesDatabaseにeach_documentというメソッドを用意しているので、DB内の文書をなめるにはこれだけでいい。 NotesDatabaseを手に入れるのは、ns.database(filename)でOK。

  ns = Notesgrip::NotesSession.new
  db = ns.database("technotes", "names.nsf")
  
  db.each_document {|doc|
    p doc
  }
  

ビューを使って文書をなめるなら、これ。NotesViewを手に入れて、view.each_documentでビューの中の文書をなめることができる。

  ns = Notesgrip::NotesSession.new
  db = ns.database("technotes", "names.nsf")
  view = db.view("People")
  view.each_document {|doc|
    p doc
  }
  

ビューを使った文書の検索

ビューの列での検索もできる。検索結果はNotesDocumentCollection。列を使った検索には、NotesViewクラスのGetAllDocumentsByKeyを使う。

  ns = Notesgrip::NotesSession.new
  db = ns.database("technotes", "names.nsf")
  view = db.view("People")
  docList = view.GetAllDocumentsByKey(["Administrator"], false)
  puts "docList.size = #{docList.size}"
  docList.each {|doc|
    p doc
  }
  

全文検索も可能。

  ns = Notesgrip::NotesSession.new
  db = ns.database("technotes", "names.nsf")
  view = db.view("People")
  match_count = view.FTSearch("miwa_dankichi.tech-notes.org")
  puts "match_count = #{match_count}"
  # 全文検索後、viewには検索にマッチしたものだけが残る
  puts "After FTSearch, view.size = #{view.size}"
  view.each_document {|doc|
    p doc
  }
  # 検索結果をクリア
  view.clear
  

効率は悪いが、ビュー内の文書を全部チェックして、条件に合う文書を見つけることもできる。

doc[fieldname]はフィールドであるNotesItemを返す。doc[fieldname].textはそのフィールドに格納されている文字列を返す。

  ns = Notesgrip::NotesSession.new
  db = ns.database("technotes", "names.nsf")
  view = db.view("People")
  view.each_document {|doc|
    if doc['LastName'].text == "hogehoge.tech-notes.org"
      doc['Mark'].text = "checked"
      doc.Save
    end
  }
  

文書を作成

  ns = Notesgrip::NotesSession.new
  db = ns.database("technotes", "names.nsf")
  doc = db.CreateDocument("Person")
  doc['LastName'].text = "hogehoge.tech-notes.org"
  doc['HTTPPassword'].text = ns.HashPassword("password")
  doc.save
  

リッチテキスト

  ns = Notesgrip::NotesSession.new
  db = ns.database("technotes", "call.nsf")
  doc = db.CreateDocument("main")
  doc['Subject'].text = "RichText TEST"
  body = doc.CreateRichTextItem( "body" )
  body.text = "Hello, RichText\n"
  body.AddFile("./sample.jpg")
  doc.save