PowerShellで作るdeliciousクライアント その3
前回の続きです。
前回でブックマークの一覧を取得できるようにしましたが、あのままではURLがわかってもブラウザで開くという作業が面倒なので、その辺を簡略化できるように与えられたURLを既定のブラウザで開くコマンドレットを作っておきます。
「Commands」というフォルダを作成して、その中に「BrowseObjectCommand.vb」というファイル名でクラスファイルを追加します。
Commands\BrowseObjectCommand.vb
Namespace Commands <Cmdlet("Browse", "Object")> _ Public Class BrowseObjectCommand Inherits PSCmdlet Private _url As String <Parameter(Mandatory:=True, Position:=0, ValueFromPipelineByPropertyName:=True)> _ Public Property Url() As String Get Return _url End Get Set(ByVal value As String) _url = value End Set End Property Protected Overrides Sub ProcessRecord() Process.Start(Me.Url) End Sub End Class End Namespace
PSCmdletクラスを継承します。コマンドレットである事を示す為にCmdletAttribute属性でマークしておきます。引数にはコマンドレットの動詞と名詞を指定します(Browse-Objectという書式になる)。
コマンドレットが実行されるとProcessRecordメソッドが呼び出されるので、これをオーバーライドして、その中ではURLプロパティの値をシェルで呼び出すだけです。
URLプロパティはParameterAttribute属性でマークして、必須属性(Mandatory:=True)、位置が0(Position:=0)、値をパイプラインから取得し、そのオブジェクトのプロパティと結びつけます(ValueFromPipelineByPropertyName:=True)。
このコマンドレットを使うと以下のようにして、URLをブラウザで開くことができるようになります。
PS delicious:\> dir -Count 1 | Browse-Object
ブックマークの追加・編集
ブックマークの追加・編集機能を実装します。
DeliciousクラスにAddBookmarkという名前で引数にDeliciousBookmark型を受け取るメソッドを定義します。
Delicious.vb
Sub AddBookmark(ByVal bookmark As DeliciousBookmark, _ Optional ByVal share As Boolean = False, Optional ByVal replace As Boolean = False) Dim address = "https://api.del.icio.us/v1/posts/add" Dim queries = New Dictionary(Of String, Object)() If String.IsNullOrEmpty(bookmark.Url) Then Throw New ArgumentException("[Url]を指定して下さい。") If String.IsNullOrEmpty(bookmark.Title) Then Throw New ArgumentException("[Title]を指定して下さい。") queries.Add("url", bookmark.Url) queries.Add("description", bookmark.Title) ' optional If Not String.IsNullOrEmpty(bookmark.Comment) Then queries.Add("extended", bookmark.Comment) If Not bookmark.Tags Is Nothing AndAlso bookmark.Tags.Length > 0 Then queries.Add("tags", String.Join(" ", bookmark.Tags)) End If If Not bookmark.Date Is Nothing Then queries.Add("dt", bookmark.Date.Value.ToString("yyyy-MM-ddTHH:mm:ssZ")) End If queries.Add("shared", IIf(share, "yes", "no")) queries.Add("replace", IIf(replace, "yes", "no")) Dim wc = New Net.WebClient() wc.Credentials = _credential wc.Encoding = Text.Encoding.UTF8 Dim contents = wc.DownloadString(JoinQueries(address, queries)) Dim result = Text.RegularExpressions.Regex.Match( _ contents, "<result code=""(?<msg>.*?)"" />", Text.RegularExpressions.RegexOptions.Multiline _ ) If result.Success Then Dim msg = result.Groups("msg").Value ' replaceを指定してね! If msg <> "done" Then Throw New ArgumentException(msg) End If End Sub Private Shared Function JoinQueries(ByVal address As String, ByVal queries As IDictionary(Of String, Object)) If queries.Count = 0 Then Return address Return address + "?" + String.Join( _ "&", queries.Select( _ Function(q) String.Format("{0}={1}", q.Key, Web.HttpUtility.UrlEncode(q.Value)) _ ).ToArray() _ ) End Function
特に説明する必要は無いでしょう。単に「https://api.del.icio.us/v1/posts/add」というURLにリクエストを送っているだけです。
あと、JoinQueriesメソッドのq.Valueを取得する部分をHttpUtilityクラスを使ってURLエンコードしておきました(System.Webアセンブリへの参照が必要です)。
使うとしたら、以下のようになるでしょうか。
Program.vb
Sub Main() Dim obj = New Delicious(New Net.NetworkCredential("ユーザ名", "パスワード")) Dim bookmark = New DeliciousBookmark With { _ .Title = "google", _ .Url = "http://www.google.co.jp" _ } ' 共有して、上書きする。 obj.AddBookmark(bookmark, share:=True, replace:=True) End Sub
では、このメソッドをプロバイダークラスから呼び出すように変更しましょう。
このメソッドを呼び出すには山ほどパラメータが必要になるので 、(インナークラスで)パラメータクラスを作っておきます。
Delicious.vb
Private Class NewItemParameters Private _url As String <Parameter(Mandatory:=True, Position:=0)> _ Public Property Url() As String Get Return _url End Get Set(ByVal value As String) _url = value End Set End Property Private _tags As String() <Parameter(Position:=1)> _ Public Property Tags() As String() Get Return _tags End Get Set(ByVal value As String()) _tags = value End Set End Property Private _comment As String <Parameter(Position:=2)> _ Public Property Comment() As String Get Return _comment End Get Set(ByVal value As String) _comment = value End Set End Property Private _date As DateTime? <Parameter(Position:=3)> _ Public Property [Date]() As DateTime? Get Return _date End Get Set(ByVal value As DateTime?) _date = value End Set End Property Private _share As SwitchParameter <Parameter()> _ Public Property Share() As SwitchParameter Get Return _share End Get Set(ByVal value As SwitchParameter) _share = value End Set End Property End Class
URL、Tags、Comment、Date、Shareというプロパティを定義しています。それぞれParameterAttribute属性でマークして、必須属性にはMandatory:=TrueをPostion:=nで順番を指定しています。
後はNewItem(New-Itemコマンドレットに対応)メソッドをオーバーライドして、その中でAddBookmarkメソッドを呼び出すだけです。
NewItemDynamicParametersメソッドをオーバーライドして、NewItemParametersクラスのインスタンスを返しておく事をお忘れなく。
Delicious.vb
Protected Overrides Sub NewItem(ByVal path As String, ByVal itemTypeName As String, ByVal newItemValue As Object) Dim dynaParams = CType(Me.DynamicParameters, NewItemParameters) Dim bookmark = New DeliciousBookmark With { _ .Title = path, _ .Url = dynaParams.Url, _ .Tags = dynaParams.Tags, _ .Comment = dynaParams.Comment, _ .Date = dynaParams.Date _ } Me.Delicious.AddBookmark( _ bookmark, replace:=Me.Force, share:=dynaParams.Share.IsPresent _ ) WriteItemObject(bookmark, path, False) End Sub Protected Overrides Function NewItemDynamicParameters(ByVal path As String, ByVal itemTypeName As String, ByVal newItemValue As Object) As Object Return New NewItemParameters() End Function
追加に成功すれば(例外が投げられなければ)、DeliciousBookmarkオブジェクトをパイプラインに出力しておきます。
これで、以下のようにしてブックマークを追加する事ができるようになります。
PS delicious:\> ni google http://www.google.co.jp -Tags google -Comment テストです。 タイトル : google URL : http://www.google.co.jp コメント : テストです。 タグ : {google} 更新日付 : PS delicious:\> dir -Count 1 タイトル : google URL : http://www.google.co.jp/ コメント : テストです。 タグ : {google} 更新日付 : 2009/03/12 4:30:46
次はブックマークを編集できるようにしておきます。
まずはSet-Itemコマンドレットのパラメータクラスをインナークラスで定義しておきます。
Delicious.vb
Private Class SetItemParameters Private _bookmark As DeliciousBookmark <Parameter(Mandatory:=True, Position:=0, ValueFromPipeline:=True)> _ Public Property Bookmark() As DeliciousBookmark Get Return _bookmark End Get Set(ByVal value As DeliciousBookmark) _bookmark = value End Set End Property Private _share As SwitchParameter <Parameter(Position:=1)> _ Public Property Share() As SwitchParameter Get Return _share End Get Set(ByVal value As SwitchParameter) _share = value End Set End Property End Class
BookmarkとShareというプロパティを定義しています。BookmarkプロパティはValueFromPipeline:=Trueにする事でパイプラインから取得できるようにしておきます。
後はSetItemメソッド(Set-Itemコマンドレットに対応)をオーバーライドして、その中でAddBookmarkメソッドをreplace:=Trueで呼び出しています。
Delicious.vb
Protected Overrides Sub SetItem(ByVal path As String, ByVal value As Object) Dim dynaParams = CType(Me.DynamicParameters, SetItemParameters) Me.Delicious.AddBookmark( _ dynaParams.Bookmark, replace:=True, share:=dynaParams.Share.IsPresent _ ) End Sub Protected Overrides Function SetItemDynamicParameters(ByVal path As String, ByVal value As Object) As Object Return New SetItemParameters() End Function
あと、Deliciousプロパティに一部不具合があったので、以下のように修正しておいて下さい。
Delicious.vb
Private _delicious As Delicious Public ReadOnly Property Delicious() As Delicious Get If _delicious Is Nothing Then ' Me.PSDriveInfoプロパティでは駄目!! Dim driveInfo = Me.SessionState.Drive.Current _delicious = New Delicious(driveInfo.Credential.GetNetworkCredential()) End If Return _delicious End Get End Property
これで、以下のようにしてブックマークの情報を編集する事ができるようになります。
PS delicious:\> $bookmark = dir -Count 1 PS delicious:\> $bookmark.Title = "google.co.jp" PS delicious:\> $bookmark | si
更新系のコマンドレットには、他にもRename-ItemとMove-Itemがありますが、これらには対応しない事にします。
次はブックマークの削除機能を実装します。
次回に続く