PowerShellで作るdeliciousクライアント ラスト

前回の続きです。

タグの一覧を取得

タグの一覧を取得する機能を実装します。

まずは「DeliciousTag.vb」というファイル名でクラスファイルを追加します。

DeliciousTag.vb
Public Class DeliciousTag
     Private _name As String

     Public Property Name() As String
         Get
             Return _name
         End Get
         Set(ByVal value As String)
             _name = value
         End Set
     End Property

     Private _count As Integer
     Public Property Count() As Integer
         Get
             Return _count
         End Get
         Set(ByVal value As Integer)
             _count = value
         End Set
     End Property
End Class

このクラスはタグの情報を格納します。

DeliciousクラスにGetTagsという名前でメソッドを定義します。

Delicious.vb
Function GetTags() As List(Of DeliciousTag)
     Dim address = "https://api.del.icio.us/v1/tags/get"

     Dim contents = GetContents(address)
     Dim xml = XDocument.Parse(contents)
     Dim results = From ele In xml.Descendants("tag") _
                   Select New DeliciousTag With { _
                     .Name = ele.Attribute("tag"), _
                     .Count = ele.Attribute("count") _
                   }

     Return results.ToList()
End Function

Private Function GetContents(ByVal address As String)
     Dim wc = New Net.WebClient()
     wc.Credentials = _credential
     wc.Encoding = Text.Encoding.UTF8

     Return wc.DownloadString(address)
End Function

処理的には特に説明する必要がありませんね。

ちなみにWebClientを使ってリクエストを送る処理をGetContentsというメソッドに分離しておきました。

後は、このメソッドをプロバイダークラスから呼び出すように変更します。

GetChildItemsParametersクラスにTagOnlyというプロパティを追加します。 このパラメータが指定された時だけタグ一覧を出力するという感じです。

DeliciousProvider.vb

Private Class GetChildItemsParameters
     Private _start As Integer = 0
     <Parameter(Position:=0)> _
     Public Property Start() As Integer
         Get
             Return _start
         End Get
         Set(ByVal value As Integer)
             _start = value
         End Set
     End Property

     Private _count As Integer = 20
     <Parameter(Position:=1)> _
     Public Property Count() As Integer
         Get
             Return _count
         End Get
         Set(ByVal value As Integer)
             _count = value
         End Set
     End Property

     Private _tag As String()
     <Parameter(Position:=2)> _
     Public Property Tag() As String()
         Get
             Return _tag
         End Get
         Set(ByVal value As String())
             _tag = value
         End Set
     End Property

     Private _tagOnly As SwitchParameter
     <Parameter()> _
     Public Property TagOnly() As SwitchParameter
         Get
             Return _tagOnly
         End Get
         Set(ByVal value As SwitchParameter)
             _tagOnly = value
         End Set
     End Property
End Class

GetChildItemsメソッドを以下のように変更します。

DeliciousProvider.vb

Protected Overrides Sub GetChildItems(ByVal path As String, ByVal recurse As Boolean)
     Dim dynaParams = CType(DynamicParameters, GetChildItemsParameters)

     If dynaParams.TagOnly.IsPresent Then
         For Each tag In Me.Delicious.GetTags()
             WriteItemObject(tag, path, False)
         Next
     Else
         For Each bookmark In Me.Delicious.GetBookmarks(dynaParams.Start, dynaParams.Count, dynaParams.Tag)
             WriteItemObject(bookmark, path, False)
         Next
     End If
End Sub

TagOnlyプロパティが指定された時だけタグを取得して、出力していますね。

タグの情報を見易く表示する為に書式設定ファイルにDeliciousTagクラスの設定を追加しておきます。

psdelicious.format.ps1xml

<?xml version="1.0" encoding="utf-8" ?>
<Configuration>
     <ViewDefinitions>
         <View>
             <Name>Tags</Name>
             <ViewSelectedBy>
                 <TypeName>PSDelicious.DeliciousTag</TypeName>
             </ViewSelectedBy>
             <TableControl>
                 <TableHeaders>
                     <TableColumnHeader>
                         <Label>タグ名</Label>
                     </TableColumnHeader>
                     <TableColumnHeader>
                         <Label>タグ数</Label>
                     </TableColumnHeader>
                 </TableHeaders>
                 <TableRowEntries>
                     <TableRowEntry>
                         <TableColumnItems>
                             <TableColumnItem>
                                 <PropertyName>Name</PropertyName>
                             </TableColumnItem>
                             <TableColumnItem>
                                 <PropertyName>Count</PropertyName>
                             </TableColumnItem>
                         </TableColumnItems>
                     </TableRowEntry>
                 </TableRowEntries>
             </TableControl>
         </View>
         <View>
             <Name>Tags</Name>
             <ViewSelectedBy>
                 <TypeName>PSDelicious.DeliciousBookmark</TypeName>
             </ViewSelectedBy>
             <ListControl>
                 <ListEntries>
                     <ListEntry>
                         <ListItems>
                             <ListItem>
                                 <Label>タイトル</Label>
                                 <PropertyName>Title</PropertyName>
                             </ListItem>
                             <ListItem>
                                 <Label>URL</Label>
                                 <PropertyName>Url</PropertyName>
                             </ListItem>
                             <ListItem>
                                 <Label>コメント</Label>
                                 <PropertyName>Comment</PropertyName>
                             </ListItem>
                             <ListItem>
                                 <Label>タグ</Label>
                                 <PropertyName>Tags</PropertyName>
                             </ListItem>
                             <ListItem>
                                 <Label>更新日付</Label>
                                 <PropertyName>Date</PropertyName>
                             </ListItem>
                         </ListItems>
                     </ListEntry>
                 </ListEntries>
             </ListControl>
         </View>
     </ViewDefinitions>
</Configuration>

これで、以下のようにするとタグの一覧を表示することができます。

PS  > dir -TagOnly

タグ名                                  タグ数
------                                  ------
.NET                                    67
ADO.NET                                 3
AIR                                     2
AOP                                     1
API                                     2
ASP.NET                                 19
ActionScript                            1
Ajax                                    2
Apache                                  3
AppEngine                               4

残りの機能を一気に実装します。

タグの編集と削除

DeliciousクラスにDeleteTagRenameTagというメソッドを追加します。

Delicious.vb
Sub DeleteTag(ByVal tag As String)
     Dim address = "https://api.del.icio.us/v1/tags/delete?tag=" + Web.HttpUtility.UrlEncode(tag)

     Dim contents = GetContents(address)
     Dim result = GetResult(contents)

     If result <> "done" Then Throw New ArgumentException(result)
End Sub

Sub RenameTag(ByVal oldValue As String, ByVal newValue As String)
     Dim address = String.Format( _
         "https://api.del.icio.us/v1/tags/rename?old={0}&new={1}", _
         Web.HttpUtility.UrlEncode(oldValue), Web.HttpUtility.UrlEncode(newValue) _
     )
     Dim contents = GetContents(address)
     Dim result = GetResult(contents)

     If result <> "done" Then Throw New ArgumentException(result)
End Sub

Private Shared Function GetResult(ByVal contents As String) As String
     Dim result = Text.RegularExpressions.Regex.Match( _
         contents, "<result>(?<msg>.*?)</result>", Text.RegularExpressions.RegexOptions.Multiline _
     )
     Return IIf(result.Success, result.Groups("msg").Value, String.Empty)
End Function

見たまんまですね。

RemoveItemParametersクラスにTagNameというプロパティを追加します。 このパラメータが指定されたらタグを削除するようにします。

DeliciousProvider.vb
Private Class RemoveItemParameters
     Private _bookmark As DeliciousBookmark
     <Parameter(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 _tagName As String
     <Parameter()> _
     Public Property TagName() As String
         Get
             Return _tagName
         End Get
         Set(ByVal value As String)
             _tagName = value
         End Set
     End Property
End Class

RemoveItemメソッドを以下のように変更します。

DeliciousProvider.vb
Protected Overrides Sub RemoveItem(ByVal path As String, ByVal recurse As Boolean)
     Dim dynaParams = CType(Me.DynamicParameters, RemoveItemParameters)

     If String.IsNullOrEmpty(dynaParams.TagName) Then
         Me.Delicious.DeleteBookmark(dynaParams.Bookmark.Url)
     Else
         Me.Delicious.DeleteTag(dynaParams.TagName)
     End If
End Sub

これで以下のようにして、タグを削除する事ができます。

PS delicious:\> del -Tag .NET

SetItemParametersクラスにTagというプロパティを追加します。このパラメータが指定されたらタグ名を変更するようにします。

DeliciousProvider.vb
Private Class SetItemParameters
     Private _bookmark As DeliciousBookmark
     <Parameter(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

     Private _tag As SwitchParameter
     <Parameter()> _
     Public Property Tag() As SwitchParameter
         Get
             Return _tag
         End Get
         Set(ByVal value As SwitchParameter)
             _tag = value
         End Set
     End Property
End Class

SetItemメソッドを以下のように変更します。

DeliciousProvider.vb
Protected Overrides Sub SetItem(ByVal path As String, ByVal value As Object)
     Dim dynaParams = CType(Me.DynamicParameters, SetItemParameters)

     If dynaParams.Tag.IsPresent Then
         Me.Delicious.RenameTag(path, value.ToString())
     ElseIf Not value Is Nothing Then
         Me.Delicious.AddBookmark( _
             dynaParams.Bookmark, replace:=True, share:=dynaParams.Share.IsPresent _
         )
     End If
End Sub

これで以下のようにして、タグ名を変更することができます。

PS delicious:\> si -Tag .net .net-framework

これでだいたい当初予定していた機能は実装できたはずです。インターフェースはまだまだ煮詰める余地がありますが、普通に使えると思います。

最後の方は駆け足になってしまいましたが、PowerShellでのプロバイダ開発の実際のやり方がなんとなくつかめたのではないでしょうか。今回は基本的な機能しか実装していませんが、アイデア次第でいくらでも便利にする事ができます。

こういった拡張性の高さもPowerShellのプロバイダ開発の魅力だと思います。皆さんも試しに作ってみて下さい。楽しいですよ!!