More Fun with BottomFeeder
After this post yesterday, I thought I'd take a shot at generalizing and extnding the ad-hoc search script. So, I came up with this set of code:
First, a block that defines a "reporting" function
"creates an HTML report for the pattern match"
htmlReportBlock := [:collection | | stream out |
stream := WriteStream on: (String new: 10000).
stream nextPutAll: '<html><body'; cr; cr.
stream nextPutAll: '<p><b>Amazon Reference Report</b></p><p>'; cr; cr.
stream nextPutAll: '<table width="100%">'; cr; cr.
stream nextPutAll: '<tr>'; cr.
collection do: [:each |
| key value |
key := each key.
value := each value.
stream nextPutAll: '<td><a href="', key link, '">', key title, '</a></td>'; cr.
stream nextPutAll: '<td>'.
stream nextPutAll: value size printString.
stream nextPutAll: '&nsbp;&nsbp;('.
1 to: value size do: [:cnt | | each1 |
each1 := value at: cnt.
each1 getMyLink isNil
ifFalse: [ stream nextPutAll: '<a href="', each1 getMyLink, '">', cnt printString, '</a>&nsbp;'].
cnt = value size
ifFalse: [stream nextPutAll: ',&nsbp;']].
stream nextPutAll: ')'.
stream nextPutAll: '</td></tr><tr>'; cr].
stream nextPutAll: '</table></p>'; cr.
stream nextPutAll: '</body></html>'.
out := 'bookReport.html' asFilename writeStream.
out nextPutAll: stream contents.
out close].
That gave me a reusable block of code for simple reports. Well, marginally reusable :). Next, the basic search function, now with an inbound search string:
"execute with an inbound pattern, answers the matches" matchItemsBlock := [:pattern | | amazonCollection matches | amazonCollection := SortedCollection new sortBlock: [:a :b | a value size > b value size]. RSSFeedManager default getAllMyFeeds do: [:each | | items | items := each allItems. matches := items select: [:eachItem | | desc | desc := eachItem description. desc ifNil: [false] ifNotNil: [pattern match: desc]]. matches notEmpty ifTrue: [amazonCollection add: each->matches]]. amazonCollection].
Now, notice how that block has the resulting collection by itself on the last line? That's because blocks, by default, return the result of the last expression. Thus, we need to make sure that it does. Now that we have our functions defined, we can try them out:
"look for matching books, then report on it" | matches | matches := matchItemsBlock value: '*href*amazon*asin*'. htmlReportBlock value: matches.
That will first gather the matches, and then execute the HTML report. We can then look at in a browser, post it to a blog... whatever. What if we wanted to track book references across all of our feeds and items on an ongoing basis? Well, there's a scripting plugin for BottomFeeder - so I can create a simple script that makes use of these functions to create a local feed:
"create a local RSS feed for this search" | matches | matches := matchItemsBlock value: '*href*amazon*asin*'. out := 'bookReport.xml' asFilename writeStream. matches := matchItemsBlock value: '*href*amazon*asin*'. [writer := RSS20_SAXWriter new output: out. writer prolog. writer startRSS. writer startChannel. writer title: 'Amazon Book Report'. writer description: 'Amazon Book Report for:', Core.Date today printString. writer pubDate: Core.Timestamp now. matches do: [:each | | items | items := each value. items do: [:eachItem | writer startItem. writer link: eachItem link. writer title: eachItem title. writer guid: eachItem guid. writer pubDate: eachItem pubDateString. writer description: eachItem description. writer category: eachItem category. writer author: eachItem author. writer endItem]]. writer endChannel. writer endRSS] ensure: [out close].
If I stick that in my "scripts" directory, I can use the script tool to add it to the set of running scripts. Now I can add this feed to BottomFeeder via a file URL, and have immediate access to all book referencing items. Pretty neat.

