tdiary-contrib 3.2.2.20130518

Sign up to get free protection for your applications and to get access to all the features.
Files changed (393) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +1 -0
  3. data/.travis.yml +7 -0
  4. data/Gemfile +13 -0
  5. data/Gemfile.lock +35 -0
  6. data/README.en.md +12 -0
  7. data/README.md +13 -0
  8. data/Rakefile +41 -0
  9. data/doc/en/filter/spambayes.txt +3 -0
  10. data/doc/en/plugin.txt +1 -0
  11. data/doc/en/style/hatena.txt +10 -0
  12. data/doc/en/style/markdown.txt +16 -0
  13. data/doc/en/util.txt +1 -0
  14. data/doc/ja/filter/antirefspam.history.txt +59 -0
  15. data/doc/ja/filter/antirefspam.txt +86 -0
  16. data/doc/ja/filter/comment_key.ja.html +182 -0
  17. data/doc/ja/filter/spambayes.txt +3 -0
  18. data/doc/ja/plugin/add_bookmark.txt +50 -0
  19. data/doc/ja/plugin/category_to_tag.txt +21 -0
  20. data/doc/ja/plugin/cocoment.txt +31 -0
  21. data/doc/ja/plugin/google_adsense.txt +25 -0
  22. data/doc/ja/plugin/google_analytics.txt +7 -0
  23. data/doc/ja/plugin/image_detail.txt +69 -0
  24. data/doc/ja/plugin/image_gps.txt +36 -0
  25. data/doc/ja/plugin/image_gps2.txt +41 -0
  26. data/doc/ja/plugin/livedoor_weather.txt +105 -0
  27. data/doc/ja/plugin/opensearch_ad.txt +16 -0
  28. data/doc/ja/plugin/section_footer.txt +84 -0
  29. data/doc/ja/plugin/select_theme.txt +1 -0
  30. data/doc/ja/plugin.txt +13 -0
  31. data/doc/ja/style/hatena.txt +10 -0
  32. data/doc/ja/style/markdown.txt +13 -0
  33. data/doc/ja/util.txt +12 -0
  34. data/filter/antirefspam.rb +263 -0
  35. data/filter/commentkey.rb +29 -0
  36. data/filter/commentsize.rb +18 -0
  37. data/filter/hidecomment.rb +13 -0
  38. data/filter/iplookup.rb +55 -0
  39. data/filter/plugin/antirefspam.rb +59 -0
  40. data/filter/plugin/commentkey.rb +58 -0
  41. data/filter/plugin/commentsize.rb +12 -0
  42. data/filter/plugin/en/iplookup.rb +9 -0
  43. data/filter/plugin/en/spambayes.rb +123 -0
  44. data/filter/plugin/iplookup.rb +39 -0
  45. data/filter/plugin/ja/antirefspam.rb +91 -0
  46. data/filter/plugin/ja/commentkey.rb +17 -0
  47. data/filter/plugin/ja/commentsize.rb +6 -0
  48. data/filter/plugin/ja/iplookup.rb +9 -0
  49. data/filter/plugin/ja/spambayes.rb +124 -0
  50. data/filter/plugin/spambayes.rb +501 -0
  51. data/filter/plugin/zh/iplookup.rb +9 -0
  52. data/filter/rblcheck.rb +36 -0
  53. data/filter/spambayes.rb +535 -0
  54. data/filter/spamlookup.rb +37 -0
  55. data/io/dbi_io/ChangeLog +19 -0
  56. data/io/dbi_io/README.ja +39 -0
  57. data/io/dbi_io/dbi_io.rb +181 -0
  58. data/io/dbi_io/plugin/refererDbiIO.rb +76 -0
  59. data/io/dbi_io/tdiary_table.sql +42 -0
  60. data/js/appstore.js +109 -0
  61. data/js/datepicker.js +69 -0
  62. data/js/editor.js +82 -0
  63. data/js/flickr.js +157 -0
  64. data/js/image_ex.js +79 -0
  65. data/js/jquery.socialbutton.js +842 -0
  66. data/js/nicovideo.js +17 -0
  67. data/js/picasa.js +322 -0
  68. data/js/plugin_checker.js +71 -0
  69. data/js/prettify/lang-apollo.js +2 -0
  70. data/js/prettify/lang-clj.js +18 -0
  71. data/js/prettify/lang-css.js +2 -0
  72. data/js/prettify/lang-go.js +1 -0
  73. data/js/prettify/lang-hs.js +2 -0
  74. data/js/prettify/lang-lisp.js +3 -0
  75. data/js/prettify/lang-lua.js +2 -0
  76. data/js/prettify/lang-ml.js +2 -0
  77. data/js/prettify/lang-n.js +4 -0
  78. data/js/prettify/lang-proto.js +1 -0
  79. data/js/prettify/lang-scala.js +2 -0
  80. data/js/prettify/lang-sql.js +2 -0
  81. data/js/prettify/lang-tex.js +1 -0
  82. data/js/prettify/lang-vb.js +2 -0
  83. data/js/prettify/lang-vhdl.js +3 -0
  84. data/js/prettify/lang-wiki.js +2 -0
  85. data/js/prettify/lang-xq.js +3 -0
  86. data/js/prettify/lang-yaml.js +2 -0
  87. data/js/prettify/prettify.css +1 -0
  88. data/js/prettify/prettify.js +28 -0
  89. data/js/referer.js +17 -0
  90. data/js/show_and_hide.js +39 -0
  91. data/js/socialbutton.js +126 -0
  92. data/js/twitter_anywhere.js +28 -0
  93. data/js/yahoo_kousei.js +21 -0
  94. data/lib/bayes/convert.rb +34 -0
  95. data/lib/bayes.rb +232 -0
  96. data/lib/exifparser/BUGS +1 -0
  97. data/lib/exifparser/ChangeLog +169 -0
  98. data/lib/exifparser/README +15 -0
  99. data/lib/exifparser/install.rb +1015 -0
  100. data/lib/exifparser/lib/exifparser/makernote/canon.rb +502 -0
  101. data/lib/exifparser/lib/exifparser/makernote/fujifilm.rb +415 -0
  102. data/lib/exifparser/lib/exifparser/makernote/minolta.rb +84 -0
  103. data/lib/exifparser/lib/exifparser/makernote/mk_nikonflensname.rb +39 -0
  104. data/lib/exifparser/lib/exifparser/makernote/nikon.rb +267 -0
  105. data/lib/exifparser/lib/exifparser/makernote/nikon2.rb +581 -0
  106. data/lib/exifparser/lib/exifparser/makernote/nikonflensname.rb +438 -0
  107. data/lib/exifparser/lib/exifparser/makernote/olympus.rb +225 -0
  108. data/lib/exifparser/lib/exifparser/makernote/prove.rb +84 -0
  109. data/lib/exifparser/lib/exifparser/makernote/sigma.rb +237 -0
  110. data/lib/exifparser/lib/exifparser/pre-setup.rb +1 -0
  111. data/lib/exifparser/lib/exifparser/scan.rb +278 -0
  112. data/lib/exifparser/lib/exifparser/tag.rb +2298 -0
  113. data/lib/exifparser/lib/exifparser/thumbnail.rb +76 -0
  114. data/lib/exifparser/lib/exifparser/utils.rb +88 -0
  115. data/lib/exifparser/lib/exifparser.rb +265 -0
  116. data/lib/exifparser/sample/exifview.rb +279 -0
  117. data/lib/tdiary-contrib.rb +19 -0
  118. data/lib/wgs2tky.rb +93 -0
  119. data/misc/section_footer2/buzzurl.yaml +6 -0
  120. data/misc/section_footer2/fc2.yaml +6 -0
  121. data/misc/section_footer2/ldc.yaml +6 -0
  122. data/misc/section_footer2/retweet.yaml +7 -0
  123. data/misc/section_footer2/twitter.yaml +7 -0
  124. data/misc/section_footer2/yahoo.yaml +6 -0
  125. data/misc/tdiarygraph/tdiarygraph120x90e.swf +0 -0
  126. data/misc/tdiarygraph/tdiarygraph125x125e.swf +0 -0
  127. data/misc/tdiarygraph/tdiarygraph240x180e.swf +0 -0
  128. data/misc/tdiarygraph/tdiarygraph468x60e.swf +0 -0
  129. data/misc/tdiarygraph/tdiarygraph728x90e.swf +0 -0
  130. data/misc/tdiarytimes/tdiarytimes125x125r.swf +0 -0
  131. data/misc/tdiarytimes/tdiarytimes125x125r7.swf +0 -0
  132. data/misc/tdiarytimes/tdiarytimes125x125s.swf +0 -0
  133. data/misc/tdiarytimes/tdiarytimes125x30.swf +0 -0
  134. data/misc/tdiarytimes/tdiarytimes234x30.swf +0 -0
  135. data/misc/tdiarytimes/tdiarytimes468x30.swf +0 -0
  136. data/plugin/add_bookmark.rb +89 -0
  137. data/plugin/apple_webclip.rb +26 -0
  138. data/plugin/appstore.rb +47 -0
  139. data/plugin/bigpresen.rb +86 -0
  140. data/plugin/bitly.rb +39 -0
  141. data/plugin/bootstrap-navi.rb +54 -0
  142. data/plugin/canonical.rb +9 -0
  143. data/plugin/category_similar.rb +73 -0
  144. data/plugin/category_to_tag.rb +60 -0
  145. data/plugin/category_to_tagcloud.rb +172 -0
  146. data/plugin/cocomment.rb +37 -0
  147. data/plugin/code-prettify.rb +23 -0
  148. data/plugin/coderwall.rb +34 -0
  149. data/plugin/datepicker.rb +28 -0
  150. data/plugin/day2section.rb +20 -0
  151. data/plugin/del_footer.rb +111 -0
  152. data/plugin/description_from_body.rb +23 -0
  153. data/plugin/development.rb +16 -0
  154. data/plugin/editor.rb +11 -0
  155. data/plugin/en/add_bookmark.rb +20 -0
  156. data/plugin/en/del_footer.rb +10 -0
  157. data/plugin/en/git-register.rb +3 -0
  158. data/plugin/en/livedoor_weather.rb +25 -0
  159. data/plugin/en/microsummary.rb +18 -0
  160. data/plugin/en/nicovideo.rb +38 -0
  161. data/plugin/en/openid.rb +8 -0
  162. data/plugin/en/section_footer.rb +6 -0
  163. data/plugin/en/section_footer2.rb +3 -0
  164. data/plugin/en/socialbutton.rb +5 -0
  165. data/plugin/everytrail.rb +39 -0
  166. data/plugin/facebook_comments.rb +59 -0
  167. data/plugin/flickr.rb +209 -0
  168. data/plugin/gist.rb +16 -0
  169. data/plugin/git-register.rb +240 -0
  170. data/plugin/github_badge.rb +27 -0
  171. data/plugin/github_link.rb +9 -0
  172. data/plugin/goo_gl.rb +42 -0
  173. data/plugin/google_adsense.rb +132 -0
  174. data/plugin/google_analytics.rb +39 -0
  175. data/plugin/google_map.rb +168 -0
  176. data/plugin/google_sitemaps.rb +60 -0
  177. data/plugin/google_webmaster.rb +22 -0
  178. data/plugin/hatena_bookmark_nocomment.rb +9 -0
  179. data/plugin/hatena_star.rb +66 -0
  180. data/plugin/hb_footer.rb +255 -0
  181. data/plugin/hb_footer4sec.rb +244 -0
  182. data/plugin/hb_footer4sec_js.rb +30 -0
  183. data/plugin/hide_comment_form.rb +4 -0
  184. data/plugin/hide_sidebar_iphone.rb +21 -0
  185. data/plugin/iddy.rb +81 -0
  186. data/plugin/image_detail.rb +143 -0
  187. data/plugin/image_ex.rb +462 -0
  188. data/plugin/image_gps.rb +128 -0
  189. data/plugin/inline_wiki.rb +6 -0
  190. data/plugin/instagr.rb +64 -0
  191. data/plugin/ja/add_bookmark.rb +20 -0
  192. data/plugin/ja/del_footer.rb +10 -0
  193. data/plugin/ja/flickr.rb +62 -0
  194. data/plugin/ja/git-register.rb +3 -0
  195. data/plugin/ja/google_sitemaps.rb +35 -0
  196. data/plugin/ja/livedoor_weather.rb +25 -0
  197. data/plugin/ja/microsummary.rb +18 -0
  198. data/plugin/ja/nicovideo.rb +41 -0
  199. data/plugin/ja/openid.rb +7 -0
  200. data/plugin/ja/section_footer.rb +6 -0
  201. data/plugin/ja/section_footer2.rb +4 -0
  202. data/plugin/ja/socialbutton.rb +6 -0
  203. data/plugin/jdate.rb +20 -0
  204. data/plugin/jholiday.rb +16 -0
  205. data/plugin/jmonth.rb +20 -0
  206. data/plugin/jquery_ui_theme.rb +55 -0
  207. data/plugin/jroku.rb +28 -0
  208. data/plugin/jyear.rb +37 -0
  209. data/plugin/latlonglab_route.rb +25 -0
  210. data/plugin/lazy_referer.rb +38 -0
  211. data/plugin/livedoor_weather.rb +180 -0
  212. data/plugin/make_link.rb +44 -0
  213. data/plugin/makerss_category.rb +43 -0
  214. data/plugin/makerss_comment.rb +35 -0
  215. data/plugin/microsummary.rb +62 -0
  216. data/plugin/mm_footer.rb +215 -0
  217. data/plugin/monthly_autopagerize.rb +67 -0
  218. data/plugin/my_hotentry.rb +132 -0
  219. data/plugin/navi_day.rb +118 -0
  220. data/plugin/navi_this_month.rb +15 -0
  221. data/plugin/nicovideo.rb +115 -0
  222. data/plugin/notify_miniblog.rb +134 -0
  223. data/plugin/ogp.rb +55 -0
  224. data/plugin/ohmsha_estore.rb +71 -0
  225. data/plugin/openid.rb +90 -0
  226. data/plugin/opensearch_ad.rb +33 -0
  227. data/plugin/picasa.rb +56 -0
  228. data/plugin/plugin_checker.rb +41 -0
  229. data/plugin/popit.rb +22 -0
  230. data/plugin/prettify.rb +19 -0
  231. data/plugin/prezi.rb +10 -0
  232. data/plugin/profile.rb +222 -0
  233. data/plugin/puboo.rb +93 -0
  234. data/plugin/pygments_css.rb +76 -0
  235. data/plugin/rating.rb +419 -0
  236. data/plugin/recent_estraier.rb +50 -0
  237. data/plugin/recent_tweet.rb +71 -0
  238. data/plugin/retweet.rb +86 -0
  239. data/plugin/rubykaigi.rb +99 -0
  240. data/plugin/search-bing.rb +87 -0
  241. data/plugin/search-default.rb +264 -0
  242. data/plugin/search-google-custom.rb +60 -0
  243. data/plugin/search-yahoo-websearch.rb +121 -0
  244. data/plugin/search-yahoo.rb +109 -0
  245. data/plugin/section_footer.rb +195 -0
  246. data/plugin/section_footer2.rb +278 -0
  247. data/plugin/section_permalink.rb +73 -0
  248. data/plugin/section_permalink_anchor.rb +39 -0
  249. data/plugin/select_style.rb +42 -0
  250. data/plugin/select_theme.rb +90 -0
  251. data/plugin/show_and_hide.rb +77 -0
  252. data/plugin/slideshare.rb +10 -0
  253. data/plugin/socialbutton.rb +60 -0
  254. data/plugin/tatsu_zine.rb +93 -0
  255. data/plugin/tdiarygraph_flashstyle.rb +296 -0
  256. data/plugin/tdiarytimes.rb +166 -0
  257. data/plugin/tdiarytimes2.rb +406 -0
  258. data/plugin/tdiarytimes_flashstyle.rb +263 -0
  259. data/plugin/tdiarytimes_textstyle.rb +290 -0
  260. data/plugin/title_anchor.rb +16 -0
  261. data/plugin/tweet_quote.rb +106 -0
  262. data/plugin/twitpic.rb +10 -0
  263. data/plugin/twitter.rb +46 -0
  264. data/plugin/twitter_anywhere.rb +209 -0
  265. data/plugin/twitter_badge.rb +42 -0
  266. data/plugin/twitter_js.rb +59 -0
  267. data/plugin/ustream.rb +19 -0
  268. data/plugin/vimeo.rb +14 -0
  269. data/plugin/volatile.rb +89 -0
  270. data/plugin/vote.rb +100 -0
  271. data/plugin/wikiloc.rb +27 -0
  272. data/plugin/windex.rb +512 -0
  273. data/plugin/yahoo_kousei.rb +79 -0
  274. data/plugin/yahoo_map.rb +97 -0
  275. data/plugin/youtube.rb +33 -0
  276. data/plugin/yshop.rb +189 -0
  277. data/plugin/zenback.rb +46 -0
  278. data/spec/apple_webclip_spec.rb +46 -0
  279. data/spec/fixtures/friendfeed.xml +2 -0
  280. data/spec/fixtures/github.json +1 -0
  281. data/spec/fixtures/twitter.xml +73 -0
  282. data/spec/gist_spec.rb +16 -0
  283. data/spec/github_link_spec.rb +39 -0
  284. data/spec/google_analytics_spec.rb +60 -0
  285. data/spec/jdate_spec.rb +23 -0
  286. data/spec/jmonth_spec.rb +28 -0
  287. data/spec/jyear_spec.rb +21 -0
  288. data/spec/my_hotentry_spec.rb +78 -0
  289. data/spec/openid_spec.rb +246 -0
  290. data/spec/opensearch_ad_spec.rb +50 -0
  291. data/spec/profile_spec.rb +88 -0
  292. data/spec/rcov.opts +2 -0
  293. data/spec/spec_helper.rb +223 -0
  294. data/spec/title_anchor_spec.rb +39 -0
  295. data/spec/twitter_js_spec.rb +116 -0
  296. data/spec/youtube_spec.rb +20 -0
  297. data/style/hatena_style.rb +1011 -0
  298. data/style/markdown_style.rb +239 -0
  299. data/style/wikiext_style.rb +21 -0
  300. data/tdiary-contrib.gemspec +25 -0
  301. data/util/clean-spam/README.ja +1 -0
  302. data/util/clean-spam/tdiary-comment-clean +46 -0
  303. data/util/clean-spam/tdiary-comment-clean2 +81 -0
  304. data/util/clean-spam/tdiary-referer-clean +46 -0
  305. data/util/convert_pstore.rb +82 -0
  306. data/util/estraier-search/ChangeLog +36 -0
  307. data/util/estraier-search/README.ja +114 -0
  308. data/util/estraier-search/en/estraier-register.rb +3 -0
  309. data/util/estraier-search/estraier-register.rb +298 -0
  310. data/util/estraier-search/estraier-search.rb +273 -0
  311. data/util/estraier-search/estraier.rhtml +73 -0
  312. data/util/estraier-search/estraier.rxml +23 -0
  313. data/util/estraier-search/i.estraier.rhtml +31 -0
  314. data/util/estraier-search/ja/estraier-register.rb +3 -0
  315. data/util/image-gallery/README.ja +27 -0
  316. data/util/image-gallery/image-gallery.rb +523 -0
  317. data/util/image-gallery/image-gallery.rb.euc-jp +523 -0
  318. data/util/image-gallery/js/SmoothGallery/Changelog +52 -0
  319. data/util/image-gallery/js/SmoothGallery/css/ReMooz.css +186 -0
  320. data/util/image-gallery/js/SmoothGallery/css/img/carrow1.gif +0 -0
  321. data/util/image-gallery/js/SmoothGallery/css/img/carrow2.gif +0 -0
  322. data/util/image-gallery/js/SmoothGallery/css/img/closebox.gif +0 -0
  323. data/util/image-gallery/js/SmoothGallery/css/img/closebox.png +0 -0
  324. data/util/image-gallery/js/SmoothGallery/css/img/fleche1.gif +0 -0
  325. data/util/image-gallery/js/SmoothGallery/css/img/fleche1.png +0 -0
  326. data/util/image-gallery/js/SmoothGallery/css/img/fleche2.gif +0 -0
  327. data/util/image-gallery/js/SmoothGallery/css/img/fleche2.png +0 -0
  328. data/util/image-gallery/js/SmoothGallery/css/img/loading-bar-black.gif +0 -0
  329. data/util/image-gallery/js/SmoothGallery/css/img/open.gif +0 -0
  330. data/util/image-gallery/js/SmoothGallery/css/img/open.png +0 -0
  331. data/util/image-gallery/js/SmoothGallery/css/img/remo_bg_e.png +0 -0
  332. data/util/image-gallery/js/SmoothGallery/css/img/remo_bg_n.png +0 -0
  333. data/util/image-gallery/js/SmoothGallery/css/img/remo_bg_ne.png +0 -0
  334. data/util/image-gallery/js/SmoothGallery/css/img/remo_bg_nw.png +0 -0
  335. data/util/image-gallery/js/SmoothGallery/css/img/remo_bg_s.png +0 -0
  336. data/util/image-gallery/js/SmoothGallery/css/img/remo_bg_se.png +0 -0
  337. data/util/image-gallery/js/SmoothGallery/css/img/remo_bg_sw.png +0 -0
  338. data/util/image-gallery/js/SmoothGallery/css/img/remo_bg_w.png +0 -0
  339. data/util/image-gallery/js/SmoothGallery/css/img/spinner.gif +0 -0
  340. data/util/image-gallery/js/SmoothGallery/css/jd.gallery.css +371 -0
  341. data/util/image-gallery/js/SmoothGallery/css/layout.css +91 -0
  342. data/util/image-gallery/js/SmoothGallery/license.txt +621 -0
  343. data/util/image-gallery/js/SmoothGallery/resizer.php +113 -0
  344. data/util/image-gallery/js/SmoothGallery/scripts/Changelog +52 -0
  345. data/util/image-gallery/js/SmoothGallery/scripts/History.Routing.js +126 -0
  346. data/util/image-gallery/js/SmoothGallery/scripts/History.js +109 -0
  347. data/util/image-gallery/js/SmoothGallery/scripts/ReMooz.js +364 -0
  348. data/util/image-gallery/js/SmoothGallery/scripts/jd.gallery.js +843 -0
  349. data/util/image-gallery/js/SmoothGallery/scripts/jd.gallery.set.js +183 -0
  350. data/util/image-gallery/js/SmoothGallery/scripts/jd.gallery.transitions.js +90 -0
  351. data/util/image-gallery/js/SmoothGallery/scripts/jdgalleryresize.js +828 -0
  352. data/util/image-gallery/js/SmoothGallery/scripts/license.txt +621 -0
  353. data/util/image-gallery/js/SmoothGallery/scripts/mootools-1.2-more.js +103 -0
  354. data/util/image-gallery/js/SmoothGallery/scripts/mootools-1.2.1-core-yc.js +349 -0
  355. data/util/image-gallery/js/SmoothGallery/scripts/resizer.php +113 -0
  356. data/util/image-gallery/misc/plugin/recent_image.rb +406 -0
  357. data/util/image-gallery/skel/gallery.rhtml +154 -0
  358. data/util/image-gallery/skel/gallery.rhtml.euc-jp +154 -0
  359. data/util/image-gallery/tdiary.conf.igsample +8 -0
  360. data/util/image-gallery/theme/image-gallery.css +85 -0
  361. data/util/image2flickr.rb +282 -0
  362. data/util/posttdiary/README.ja +12 -0
  363. data/util/posttdiary/posttdiary-ex.rb +1155 -0
  364. data/util/posttdiary/posttdiary.rb +245 -0
  365. data/util/rast-search/ChangeLog +55 -0
  366. data/util/rast-search/README.ja +99 -0
  367. data/util/rast-search/en/rast-register.rb +3 -0
  368. data/util/rast-search/i.rast.rhtml +33 -0
  369. data/util/rast-search/ja/rast-register.rb +3 -0
  370. data/util/rast-search/rast-register.rb +326 -0
  371. data/util/rast-search/rast-search.rb +249 -0
  372. data/util/rast-search/rast.rhtml +66 -0
  373. data/util/rast-search/rast.rxml +21 -0
  374. data/util/section_link/README +11 -0
  375. data/util/section_link/misc/plugin/section_link.rb +68 -0
  376. data/util/section_link/misc/plugin/section_link_anchor.rb +38 -0
  377. data/util/section_link/tdiary/tdiary_day_ext.rb +21 -0
  378. data/util/section_link/tdiary/tdiaryext_style.rb +36 -0
  379. data/util/section_link/tdiary/wikiext_style.rb +36 -0
  380. data/util/tdiary-for-ruby1.9/compatible.rb +97 -0
  381. data/util/tdiary-for-ruby1.9/tdiary-2.2.0.patch +98 -0
  382. data/util/tdiary-for-ruby1.9/tdiary-2.3.1.patch +212 -0
  383. data/util/tdiary-grep/README +4 -0
  384. data/util/tdiary-grep/grep.rb +445 -0
  385. data/util/tdiary-mode/http.el +130 -0
  386. data/util/tdiary-mode/tdiary-mode.el +613 -0
  387. data/util/tdiary-vim/ChangeLog +25 -0
  388. data/util/tdiary-vim/README +60 -0
  389. data/util/tdiary-vim/tdiary.vim +350 -0
  390. data/util/tdiarysearch/README.en +53 -0
  391. data/util/tdiarysearch/README.ja +99 -0
  392. data/util/tdiarysearch/search.rb +504 -0
  393. metadata +497 -0
@@ -0,0 +1,1011 @@
1
+ #!/usr/bin/env ruby -Ke
2
+ # Copyright(c) 2004 URABE, Shyouhei.
3
+ #
4
+ # Permission is hereby granted, free of charge, to any person obtaining a copy
5
+ # of this code, to deal in the code without restriction, including without
6
+ # limitation the rights to use, copy, modify, merge, publish, distribute,
7
+ # sublicense, and/or sell copies of the code, and to permit persons to whom the
8
+ # code is furnished to do so, subject to the following conditions:
9
+ #
10
+ # The above copyright notice and this permission notice shall be
11
+ # included in all copies or substantial portions of the code.
12
+ #
13
+ # THE CODE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14
+ # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15
+ # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16
+ # AUTHOR OR COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17
+ # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18
+ # OUT OF OR IN CONNECTION WITH THE CODE OR THE USE OR OTHER DEALINGS IN THE
19
+ # CODE.
20
+
21
+ # $Id: hatena_style.rb,v 1.12 2007-02-27 06:57:14 kazuhiko Exp $
22
+ # Hatena::Diary compatible style
23
+ # Works only under ruby 1.8.1 or later
24
+
25
+ [
26
+ 'uri',
27
+ 'net/http',
28
+ 'cgi',
29
+ 'pstore',
30
+ 'time',
31
+ ].each {|f| require f }
32
+
33
+ class TDiary::HatenaDiary
34
+ include TDiary::DiaryBase, TDiary::CategorizableDiary
35
+
36
+ def initialize(date, title, body, modified=Time.now)
37
+ init_diary
38
+ @sections = []
39
+ replace date, title, body
40
+ @last_modified = modified
41
+ end
42
+
43
+ def style
44
+ 'Hatena'
45
+ end
46
+
47
+ def replace(date, title, body)
48
+ set_date date
49
+ set_title title
50
+ @sections.clear
51
+ append body
52
+ end
53
+
54
+ def append(body, author=nil)
55
+ @sections.concat Hatena::Diary.parse(body, author)
56
+ self
57
+ end
58
+
59
+ def each_section(&block)
60
+ @sections.each(&block)
61
+ end
62
+
63
+ def to_src
64
+ @sections.inject('') {|r, i| r << i.to_src }
65
+ end
66
+
67
+ def to_html(opt, mode=:HTML)
68
+ j = 0
69
+ @sections.inject('') {|r, i|
70
+ j += 1
71
+ r << '<div class="section">' if mode != :CHTML
72
+ r << i.convert(mode, date, j, opt)
73
+ r << '</div>' if mode != :CHTML
74
+ r
75
+ }
76
+ end
77
+
78
+ def to_s
79
+ sprintf('date=%s, title=%s, body=%s',
80
+ date.strftime('%Y%m%d'),
81
+ title,
82
+ @sections.map {|i| '[%s]' % i}.join)
83
+ end
84
+ end
85
+
86
+ # This is the namespace module
87
+ module Hatena
88
+
89
+ def Hatena.conf
90
+ ObjectSpace.each_object do |diary|
91
+ next unless diary.kind_of?(TDiary::TDiaryBase)
92
+ return diary.instance_eval { @conf }
93
+ end
94
+ end
95
+
96
+ Diary = Object.new
97
+ API = Object.new
98
+
99
+ # get a text of hatena-style, and convert it into parse tree.
100
+ def Diary.parse(str, author)
101
+ str.gsub(/\r(?!\n)/,"\n")\
102
+ .delete("\r")\
103
+ .gsub(/^\*/,'**')\
104
+ .split(/^\*/)\
105
+ .inject([]) {|r, i| i.empty? ? r : r << Hatena::Section.new(i, author) }
106
+ end
107
+
108
+ # find the cache_path from entore ruby world
109
+ # could someone please tell me more eficient way to do this...
110
+ def API.cache_path
111
+ ret = Hatena.conf.cache_path || Hatena.conf.data_path + '/cache'
112
+
113
+ unless FileTest.directory?(ret)
114
+ begin
115
+ Dir.mkdir(ret)
116
+ rescue Errno::EEXIST
117
+ ; # OK
118
+ end
119
+ end
120
+ ret
121
+ end
122
+
123
+ def API.update_kw(kw)
124
+ return false if File.exist?(kw) && Time.now - File.mtime(kw) < 86400
125
+ File.open(kw, IO::WRONLY|IO::CREAT) do |fp|
126
+ break unless fp.flock(IO::LOCK_EX|IO::LOCK_NB)
127
+ uri = ::URI.parse('http://d.hatena.ne.jp/images/keyword/keywordlist')
128
+ timeout(60) do
129
+ Net::HTTP.version_1_1
130
+ Net::HTTP.new(uri.host, uri.port).start do |http|
131
+ res, body = http.get(uri.request_uri,
132
+ {'User-Agent' => "tDiary/#{TDIARY_VERSION}"})
133
+ fp.seek(0, IO::SEEK_SET)
134
+ fp.write(body)
135
+ end
136
+ end
137
+ end
138
+ true
139
+ end
140
+
141
+ def API.update_db(kw, db)
142
+ raise if API.update_kw kw
143
+ raise unless FileTest.exist? db.path
144
+ false
145
+ rescue
146
+ str = File.open(kw, IO::RDONLY) do |fp|
147
+ fp.flock(IO::LOCK_SH)
148
+ fp.read
149
+ end
150
+ a = str.gsub(/\\s/,' ') \
151
+ .gsub(/\\(?!\|)/,'') \
152
+ .scan(/(?:[^|]|\\\|)*[^\\](?=\||\z)/)
153
+ db.transaction do
154
+ db['trie'] = Trie.new(a)
155
+ end
156
+ true
157
+ end
158
+
159
+ # The trie of keywords
160
+ # Keywords are chached, chache expires every day (24h)
161
+ def API.keywords
162
+ path = API.cache_path
163
+ kw = path + '/keywordlist'
164
+ db = PStore.new(path + '/keywords.pstore')
165
+ if API.update_db(kw, db) || @ret.nil?
166
+ db.transaction(IO::RDONLY) do
167
+ @ret = db['trie']
168
+ end
169
+ end
170
+ return @ret
171
+ end
172
+ end
173
+
174
+ # Deterministic finate automata
175
+ class Hatena::Trie
176
+
177
+ private
178
+ def add(kw)
179
+ h = @hash1
180
+ kw.split(//e).each do |c|
181
+ unless h.has_key? c
182
+ tmp = Hash.new
183
+ @ary << tmp
184
+ h[c] = tmp
185
+ end
186
+ h = h[c]
187
+ end
188
+ @hash2[h] = kw
189
+ end
190
+
191
+ def initialize(a)
192
+ @ary = Array.new
193
+ @hash1 = Hash.new
194
+ @hash2 = Hash.new
195
+ a.each {|kw| add kw }
196
+ end
197
+
198
+ public
199
+ def match(str)
200
+ ret = nil
201
+ h = @hash1
202
+ a = str.split(//e)
203
+ i = 0
204
+ j = 0
205
+ while c = a[i + j]
206
+ if h[c]
207
+ h = h[c]
208
+ if @hash2[h]
209
+ ret = @hash2[h]
210
+ end
211
+ f = false
212
+ j += 1
213
+ else
214
+ return ret if ret
215
+ h = @hash1 # reset
216
+ i += 1
217
+ j = 0
218
+ end
219
+ end
220
+ return ret
221
+ end
222
+ end
223
+
224
+ # --------
225
+ # Parser Tree Nodes
226
+
227
+ class Hatena::Section
228
+ def initialize(str, author)
229
+ t = Time.now
230
+ @author = author.freeze
231
+ @src = str.gsub(/^\*t\*/, '*%d*' % t.to_i)\
232
+ .gsub(/<(ins|del)>/, '<\1 datetime="%s">' % t.xmlschema)
233
+ @tree = Hatena::Block.new(@src)
234
+ end
235
+
236
+ def convert(mode, date, i, opt)
237
+ @tree.convert(mode, date, i, opt, author)
238
+ end
239
+
240
+ def to_src
241
+ @src
242
+ end
243
+
244
+ def categories
245
+ @tree.title.categories
246
+ end
247
+
248
+ def author
249
+ @author
250
+ end
251
+
252
+ def body
253
+ @tree.body.to_s
254
+ end
255
+
256
+ def subtitle
257
+ @tree.title.to_s
258
+ end
259
+
260
+ def stripped_subtitle
261
+ @tree.title.strip.to_s
262
+ end
263
+
264
+ def body_to_html
265
+ @tree.body.convert(:HTML)
266
+ end
267
+
268
+ def subtitle_to_html
269
+ @tree.title.convert(:HTML)
270
+ end
271
+
272
+ def stripped_subtitle_to_html
273
+ @tree.title.strip.convert(:HTML)
274
+ end
275
+ end
276
+
277
+ # Block level elements
278
+ class Hatena::Block
279
+ attr_reader :to_s, :title, :body
280
+
281
+ def initialize(str) # Too long. Needs refactoring.
282
+ if str.nil?
283
+ @title = Hatena::Title.new('') # dummy
284
+ @body = Hatena::Inline.new('') # dummy
285
+ @to_s = ''
286
+ elsif str[0] == ?*
287
+ t,b = *str.split(/\n/,2)
288
+ @title = Hatena::Title.new(t)
289
+ @body = Hatena::BlockAndorInline.new(b, false)
290
+ @to_s = t + "\n" + (b||'')
291
+ else
292
+ @to_s = str
293
+ @title = Hatena::Title.new('') # dummy
294
+ @body = Hatena::BlockAndorInline.new(str, false)
295
+ end
296
+ end
297
+
298
+ def convert(mode, date=nil, i=nil, opt=nil, author=nil)
299
+ if title_is_dummy?
300
+ @body.convert(mode)
301
+ else
302
+ @title.convert(mode, date, i, opt, author) + "\n" + @body.convert(mode)
303
+ end
304
+ end
305
+
306
+ def title_is_dummy?
307
+ @to_s[0] == ?*
308
+ end
309
+ end
310
+
311
+ # Section subtitle
312
+ class Hatena::Title
313
+ attr_reader :to_s, :categories, :strip
314
+
315
+ def initialize(str)
316
+ if m = /\A\*([0-9]+)\*/.match(str)
317
+ @time = Time.at(Integer(m[1]))
318
+ @to_s = m.post_match.freeze
319
+ elsif m = /\A\*([a-zA-Z0-9_]+)\*/.match(str)
320
+ @name = m[1]
321
+ @to_s = m.post_match.freeze
322
+ else
323
+ @to_s = (str[1..-1]||'').freeze
324
+ end
325
+ @categories = to_s.scan(/\[(.*?)\]/).map{|a| a[0] }
326
+ @strip = Hatena::Inline.new(Regexp.last_match ? Regexp.last_match.post_match : to_s)
327
+ end
328
+
329
+ def convert(mode, date=nil, i=nil, opt=nil, author=nil)
330
+ id = ('p%02d' % (i || 0))
331
+ h = '%0.32b' % rand(0x100000000)
332
+ case
333
+ when date.nil?
334
+ categories.map {|i|
335
+ "<%=category_anchor <<'#{h}'.chomp\n#{i}\n#{h}\n%>"
336
+ }.join + strip.convert(mode)
337
+ when mode == :CHTML
338
+ sprintf('<H3%s><A NAME="%s">*</A>%s%s</H3>',
339
+ @name ? %Q{ ID"=#@name"} : '',
340
+ id,
341
+ (opt['multi_user'] && author) ? "[#{author}]" : '',
342
+ strip.convert(mode))
343
+ else
344
+ sprintf('<h3%s><a %shref="%s<%%=anchor "%s"%%>#%s">%s</a>%s%s%s %s</h3>',
345
+ @name ? %Q{ id="#@name"} : '',
346
+ opt['anchor'] ? 'name="%s" ' % id : '',
347
+ opt['index'],
348
+ date.strftime('%Y%m%d'),
349
+ @name || id,
350
+ opt['section_anchor'],
351
+ categories.map {|cat|
352
+ "<%=category_anchor <<'#{h}'.chomp\n#{cat}\n#{h}\n%>"
353
+ }.join,
354
+ (opt['multi_user'] && author) ? "[#{author}]" : '',
355
+ strip.convert(mode),
356
+ @time ? %Q!<span class="timestamp">#{@time.strftime('%H:%M')}</span>! : '')
357
+ end
358
+ end
359
+ end
360
+
361
+ # Sequence of block level elements and/or inline level elements
362
+ # or sequence of block level elements only.
363
+ class Hatena::BlockAndorInline
364
+ def initialize(str, allowinline = true)
365
+ @elems = Array.new
366
+ pbuffer = '' # paragraph buffer
367
+ flush_pbuffer = lambda{
368
+ next if pbuffer.empty?
369
+ if allowinline
370
+ @elems.push Hatena::Inline.new(pbuffer)
371
+ else
372
+ @elems.push Hatena::Paragraph.new(pbuffer)
373
+ end
374
+ pbuffer.replace('')
375
+ }
376
+ lines = str.concat("\n").scan(/.*\n/)
377
+ until lines.empty?
378
+ case
379
+ when lines[0][0] == ?-
380
+ flush_pbuffer.call
381
+ buffer = ''
382
+ until lines.empty?
383
+ break unless lines[0][0] == ?-
384
+ buffer.concat lines.shift
385
+ end
386
+ @elems.push Hatena::Itemize.new(buffer)
387
+ when lines[0][0] == ?+
388
+ flush_pbuffer.call
389
+ buffer = ''
390
+ until lines.empty?
391
+ break unless lines[0][0] == ?+
392
+ buffer.concat lines.shift
393
+ end
394
+ @elems.push Hatena::Enumerate.new(buffer)
395
+ when lines[0][0] == ?:
396
+ flush_pbuffer.call
397
+ buffer = ''
398
+ until lines.empty?
399
+ break unless lines[0][0] == ?:
400
+ break unless lines[0].rindex(?:) != 0
401
+ buffer.concat lines.shift
402
+ end
403
+ @elems.push Hatena::Description.new(buffer)
404
+ when lines[0] == ">>\n"
405
+ flush_pbuffer.call
406
+ buffer = ''
407
+ nest = 0
408
+ until lines.empty?
409
+ nest += 1 if lines[0] == ">>\n"
410
+ nest -= 1 if lines[0] == "<<\n"
411
+ buffer.concat lines.shift
412
+ break if nest <= 0
413
+ end
414
+ @elems.push Hatena::Quote.new(buffer)
415
+ when lines[0] == ">|\n"
416
+ flush_pbuffer.call
417
+ buffer = ''
418
+ until lines.empty?
419
+ str1 = lines.shift
420
+ buffer.concat str1
421
+ break if /\|<$/ =~ str1
422
+ end
423
+ @elems.push Hatena::Verbatim.new(buffer)
424
+ when lines[0] == ">||\n"
425
+ flush_pbuffer.call
426
+ buffer = ''
427
+ until lines.empty?
428
+ str1 = lines.shift
429
+ buffer.concat str1
430
+ break if /\|\|<$/ =~ str1
431
+ end
432
+ @elems.push Hatena::SuperVerbatim.new(buffer)
433
+ when lines[0][0,5] == '><!--'
434
+ flush_pbuffer.call
435
+ # comment, throwing away
436
+ until lines.empty?
437
+ break if /--><$/ =~ lines.shift
438
+ end
439
+ when lines[0][0,2] == '><'
440
+ flush_pbuffer.call
441
+ buffer = ''
442
+ until lines.empty?
443
+ str1 = lines.shift
444
+ buffer.concat str1
445
+ break if /><$/ =~ str1
446
+ end
447
+ @elems.push Hatena::UnParagraph.new(buffer)
448
+ else
449
+ pbuffer.concat lines.shift
450
+ if pbuffer[-3..-1] == "\n\n\n"
451
+ flush_pbuffer.call
452
+ end
453
+ end
454
+ end
455
+ flush_pbuffer.call
456
+ end
457
+
458
+ def convert(mode)
459
+ @elems.inject('') {|r, i| r << i.convert(mode) << "\n" }
460
+ end
461
+ end
462
+
463
+ # Itemize
464
+ # extension to Hatena: nest can be more than 3 level.
465
+ class Hatena::Itemize
466
+ def initialize(str)
467
+ @elems = Array.new
468
+ lines = str.gsub(/^-/,'').scan(/.*\n/)
469
+ buffer = ''
470
+ until lines.empty?
471
+ case
472
+ when lines[0][0] == ?-
473
+ until lines.empty?
474
+ break unless lines[0][0] == ?-
475
+ buffer.concat lines.shift
476
+ end
477
+ @elems.push Hatena::BlockAndorInline.new(buffer)
478
+ buffer = ''
479
+ when lines[0][0] == ?+
480
+ until lines.empty?
481
+ break unless lines[0][0] == ?+
482
+ buffer.concat lines.shift
483
+ end
484
+ @elems.push Hatena::BlockAndorInline.new(buffer)
485
+ buffer = ''
486
+ when lines[0][0] == ?:
487
+ until lines.empty?
488
+ break unless lines[0][0] == ?:
489
+ break unless lines[0].rindex(?:) != 0
490
+ buffer.concat lines.shift
491
+ end
492
+ @elems.push Hatena::BlcokAndorInline.new(buffer)
493
+ buffer = ''
494
+ else
495
+ @elems.push Hatena::Inline.new(buffer) unless buffer.empty?
496
+ buffer = lines.shift
497
+ end
498
+ end
499
+ @elems.push Hatena::Inline.new(buffer) unless buffer.empty?
500
+ end
501
+
502
+ def convert(mode)
503
+ template = nil
504
+ if mode == :CHTML
505
+ template = ["<UL>%s\n</UL>", "\n<LI>%s</LI>"]
506
+ else
507
+ template = ["<ul>%s\n</ul>", "\n<li>%s</li>"]
508
+ end
509
+ template[0] % @elems.inject('') {|r, i|
510
+ r << template[1] % i.convert(mode)
511
+ }
512
+ end
513
+ end
514
+
515
+
516
+ # Enumerate
517
+ # Extension to Hatena: nest can be more than 3 level
518
+ class Hatena::Enumerate
519
+ def initialize(str)
520
+ @elems = Array.new
521
+ lines = str.gsub(/^\+/,'').scan(/.*\n/)
522
+ buffer = ''
523
+ until lines.empty?
524
+ case
525
+ when lines[0][0] == ?-
526
+ until lines.empty?
527
+ break unless lines[0][0] == ?-
528
+ buffer.concat lines.shift
529
+ end
530
+ @elems.push Hatena::BlockAndorInline.new(buffer)
531
+ buffer = ''
532
+ when lines[0][0] == ?+
533
+ until lines.empty?
534
+ break unless lines[0][0] == ?+
535
+ buffer.concat lines.shift
536
+ end
537
+ @elems.push Hatena::BlockAndorInline.new(buffer)
538
+ buffer = ''
539
+ when lines[0][0] == ?:
540
+ until lines.empty?
541
+ break unless lines[0][0] == ?:
542
+ break unless lines[0].rindex(?:) != 0
543
+ buffer.concat lines.shift
544
+ end
545
+ @elems.push Hatena::BlcokAndorInline.new(buffer)
546
+ buffer = ''
547
+ else
548
+ @elems.push Hatena::Inline.new(buffer) unless buffer.empty?
549
+ buffer = lines.shift
550
+ end
551
+ end
552
+ @elems.push Hatena::Inline.new(buffer) unless buffer.empty?
553
+ end
554
+
555
+ def convert(mode)
556
+ template = nil
557
+ if mode == :CHTML
558
+ template = ["<OL>%s\n</OL>", "\n<LI>%s</LI>"]
559
+ else
560
+ template = ["<ol>%s\n</ol>", "\n<li>%s</li>"]
561
+ end
562
+ template[0] % @elems.inject('') {|r, i|
563
+ r << template[1] % i.convert(mode)
564
+ }
565
+ end
566
+ end
567
+
568
+ # Description list
569
+ # Extension to hatena : term only and descriotion only are OK
570
+ # :term:
571
+ # ::desc
572
+ # Extension to Hatena : can be combined with lists
573
+ class Hatena::Description
574
+ def initialize(str)
575
+ @elems = Array.new
576
+ str.each_line do |l|
577
+ raise SyntaxError unless l[0] == ?:
578
+ l = l[1..-1]
579
+ buffer = ''
580
+ # while l =~ /[^:]*#{URI.regexp}/o
581
+ # buffer.concat Regexp.last_match.to_s
582
+ # l = Regexp.last_match.post_match
583
+ # end
584
+ dt,dd = *l.split(/:/,2)
585
+ buffer.concat dt
586
+ @elems.push([
587
+ buffer.empty? ? nil : Hatena::Inline.new(buffer),
588
+ (dd.nil? || dd.empty?) ? nil : Hatena::Inline.new(dd)
589
+ ])
590
+ end
591
+ end
592
+
593
+ def convert(mode)
594
+ template = nil
595
+ if mode == :CHTML
596
+ template = ["<DL>%s\n</DL>", "\n<DT>%s</DT>", "<DD>%s</DD>"]
597
+ else
598
+ template = ["<dl>%s\n</dl>", "\n<dt>%s</dt>", "<dd>%s</dd>"]
599
+ end
600
+ template[0] % @elems.inject('') {|r, i|
601
+ r << template[1] % i[0].convert(mode) unless i[0].nil?
602
+ r << template[2] % i[1].convert(mode) unless i[1].nil?
603
+ r
604
+ }
605
+ end
606
+ end
607
+
608
+ # block level quote
609
+ # Extension to hatena : nest can be more than 2 level.
610
+ class Hatena::Quote
611
+ def initialize(str)
612
+ @elems = Hatena::Block.new(str[3..-4])
613
+ end
614
+
615
+ def convert(mode)
616
+ template = nil
617
+ if mode == :CHTML
618
+ template = "<BLOCKQUOTE>\n%s\n</BLOCKQUOTE>"
619
+ else
620
+ template = "<blockquote>\n%s\n</blockquote>"
621
+ end
622
+ sprintf(template,@elems.convert(mode))
623
+ end
624
+ end
625
+
626
+ # preformatted text
627
+ class Hatena::Verbatim
628
+ def initialize(str)
629
+ @str = str[3..-4].freeze
630
+ end
631
+
632
+ def convert(mode)
633
+ template = nil
634
+ if mode == :CHTML
635
+ template = "<PRE>%s</PRE>"
636
+ else
637
+ template = "<pre>%s</pre>"
638
+ end
639
+ sprintf(template,CGI.escapeHTML(@str))
640
+ end
641
+ end
642
+
643
+ # preformatted text
644
+ class Hatena::SuperVerbatim
645
+ def initialize(str)
646
+ @str = str[3..-5].freeze
647
+ end
648
+
649
+ def convert(mode)
650
+ template = nil
651
+ if mode == :CHTML
652
+ template = "<PRE>%s</PRE>"
653
+ else
654
+ template = "<pre>%s</pre>"
655
+ end
656
+ sprintf(template,CGI.escapeHTML(@str))
657
+ end
658
+ end
659
+
660
+ # non-paragraph blocklevel
661
+ class Hatena::UnParagraph
662
+ def initialize(str)
663
+ @elems = Hatena::Inline.new(str[1..-3])
664
+ # 0123...
665
+ # ><div>
666
+ # ... ...
667
+ # ... </div><\n
668
+ # ...-321
669
+ end
670
+
671
+ def convert(mode)
672
+ @elems.convert(mode)
673
+ end
674
+ end
675
+
676
+ # paragraph
677
+ # Extension to Hatena: not using <br> but begins next paragraph
678
+ class Hatena::Paragraph
679
+ def initialize(str)
680
+ @elems = Hatena::Inline.new(str.gsub(/\n\n\n/,''))
681
+ end
682
+
683
+ def convert(mode)
684
+ template = nil
685
+ if mode == :CHTML
686
+ template = "<P>\n%s\n</P>"
687
+ else
688
+ template = "<p>\n%s\n</p>"
689
+ end
690
+ sprintf(template, @elems.convert(mode))
691
+ end
692
+ end
693
+
694
+ # inline elements
695
+ class Hatena::Inline
696
+ def initialize(str)
697
+ @elems = Array.new
698
+ inside_a = false
699
+ return if str == "\n"
700
+ until str.empty?
701
+ case str
702
+ when /\A\[\](.*?)\[\]/m
703
+ @elems.push Hatena::CDATA.new(Regexp.last_match[1])
704
+ when /\A\)\(\((.*?)\)\)\(/m, /\A\(\(\((.*?)\)\)\)/m
705
+ @elems.push Hatena::CDATA.new('((')
706
+ @elems.push Hatena::Inline.new(Regexp.last_match[1])
707
+ @elems.push Hatena::CDATA.new('))')
708
+ when /\A\(\((.*?)\)\)/m
709
+ @elems.push Hatena::Footnote.new(Regexp.last_match[1])
710
+ when /\A#{tag_regex}/o
711
+ @elems.push Hatena::TAG.new(Regexp.last_match.to_s)
712
+ if str.index("<a") == 0
713
+ inside_a = true
714
+ elsif str.index("</a>") == 0
715
+ inside_a = false
716
+ end
717
+ when /\A\[amazon:(.*?)\]/m
718
+ @elems.push Hatena::AmazonSearch.new(Regexp.last_match[1], true)
719
+ when /\A\[google:(.*?)\]/m
720
+ @elems.push Hatena::Google.new(Regexp.last_match[1], true)
721
+ when /\A\[(?:(#{gid_regex}):)?keyword:(.*?)\]/m, /\A\[\[(.*?)\]\]/m
722
+ group, keyword = Regexp.last_match.captures
723
+ @elems.push Hatena::Keyword.new(group, keyword, true)
724
+ when /\A\[(?:(#{gid_regex}|[ad]):)?id:([a-zA-Z][-a-zA-Z0-9_]{1,30}[a-zA-Z0-9])\]/m,
725
+ /\A(?:(#{gid_regex}|[ad]):)?id:([a-zA-Z][-a-zA-Z0-9_]{1,30}[a-zA-Z0-9](?::(?:[0-9]+|about))?)/
726
+ sid, id = Regexp.last_match.captures
727
+ @elems.push Hatena::ID.new(sid, id, true)
728
+ when /\A\[(?i:ISBN|ASIN):(.*?)(?::image(?::(?:small|large))?)?\]/m,
729
+ /(?i:ISBN|ASIN):([-0-9A-Za-z]+)(?::image(?::(?:small|large))?)?/
730
+ @elems.push Hatena::Amazon.new(Regexp.last_match[1], true)
731
+ when /\A\[tex:(.*?)\]/m
732
+ @elems.push Hatena::TeX.new(Regexp.last_match[1])
733
+ when /\A#{gid_regex}/
734
+ @elems.push Hatena::Group.new(Regexp.last_match.to_s, true)
735
+ when /\A\[((?i:https?|ftp|mailto):.+?)\]/m, /\A(#{URI.regexp})/o
736
+ @elems.push Hatena::URI.new(Regexp.last_match[1])
737
+ else
738
+ /.+?(?=[\[\]()<>]|(?i:https?|ftp|mailto|id|ISBN|ASIN)|[adg]:|$)/m =~ str
739
+ if inside_a
740
+ @elems.push Hatena::CDATA.new(Regexp.last_match.to_s)
741
+ else
742
+ @elems.push Hatena::Sentence.new(Regexp.last_match.to_s)
743
+ end
744
+ end
745
+ str = Regexp.last_match.post_match
746
+ end
747
+ end
748
+
749
+ def convert(mode)
750
+ @elems.inject('') {|r, i| r << i.convert(mode) }
751
+ end
752
+
753
+ private
754
+ # tag_regex was quoted from http://www.din.or.jp/~ohzaki/perl.htm#HTML_Tag
755
+ def tag_regex
756
+ /<[^"'<>]*(?:"[^"]*"[^"'<>]*|'[^']*'[^"'<>]*)*(?:>|(?=<)|$)/
757
+ end
758
+
759
+ def gid_regex
760
+ /g:[a-zA-Z][a-zA-Z0-9]{2,23}/
761
+ end
762
+ end
763
+
764
+ # String that surely doesn't contain any keywords
765
+ # String that can contain keyword is a Sentence
766
+ class Hatena::CDATA
767
+ def initialize(str)
768
+ @str = str.freeze
769
+ end
770
+
771
+ def convert(mode)
772
+ @str
773
+ end
774
+ end
775
+
776
+ # footnote
777
+ # footnote.rb required
778
+ class Hatena::Footnote
779
+ def initialize(str)
780
+ @str = str
781
+ @heredoc = rand(0x100000000)
782
+ end
783
+
784
+ def convert(mode)
785
+ sprintf("<%%=fn <<'%0.32b'.chomp\n%s\n%0.32b\n%%>", @heredoc, @str, @heredoc)
786
+ end
787
+ end
788
+
789
+ # HTML tags
790
+ # Disadvantanegs from hatena : <hatena ...> is not supported
791
+ # Extension to Hatena : ERB expression can be written
792
+ class Hatena::TAG
793
+ def initialize(str)
794
+ @elems = Array.new
795
+ return if /<hatena/ =~ str # not implemented
796
+ while m = /"(.*?)"/.match(str)
797
+ @elems.push Hatena::CDATA.new(m.pre_match)
798
+ @elems.push Hatena::CDATA.new('"')
799
+ case m[1]
800
+ when /\Agoogle:(.*)/
801
+ @elems.push Hatena::Google.new(Regexp.last_match[1], false)
802
+ when /\Aid:([a-zA-Z][-a-zA-Z0-9_]{1,30}[a-zA-Z0-9])/
803
+ @elems.push Hatena::ID.new(Regexp.last_match[1], false)
804
+ when /\A(?:ISBN|ASIN):(.*)/i
805
+ @elems.push Hatena::Amazon.new(Regexp.last_match[1], false)
806
+ when /\Akeyword:(.*)/
807
+ @elems.push Hatena::Keyword.new(Regexp.last_match[1], false)
808
+ else
809
+ @elems.push Hatena::CDATA.new(m[1])
810
+ end
811
+ @elems.push Hatena::CDATA.new('"')
812
+ str = m.post_match
813
+ end
814
+ @elems.push Hatena::CDATA.new(str)
815
+ end
816
+
817
+ def convert(mode)
818
+ @elems.inject('') {|r, i| r << i.convert(mode) }
819
+ end
820
+ end
821
+
822
+ # URIs which appear in the sentence
823
+ class Hatena::URI
824
+ def initialize(str)
825
+ @uri = str
826
+ end
827
+
828
+ def convert(mode)
829
+ template = nil
830
+ if mode == :CHTML
831
+ template = '<A HREF="%s">%s</A>'
832
+ else
833
+ template = '<a href="%s">%s</a>'
834
+ end
835
+ sprintf(template, @uri, @uri)
836
+ end
837
+ end
838
+
839
+ # Link to Google
840
+ class Hatena::Google
841
+ def initialize(str, tag_p)
842
+ @tag_p = tag_p
843
+ @str = str
844
+ end
845
+
846
+ def convert(mode)
847
+ uri = 'http://www.google.com/search?q=%s&amp;ie=euc-jp&amp;oe=euc-jp' % URI.escape(@str, /[^-_.!~*'()a-zA-Z0-9]/)
848
+ return uri unless @tag_p
849
+ template=nil
850
+ if mode == :CHTML
851
+ template = '<A HREF="%s">google:%s</A>'
852
+ else
853
+ template = '<a href="%s">google:%s</a>'
854
+ end
855
+ sprintf(template, uri, @str)
856
+ end
857
+ end
858
+
859
+ # Link to Hatena Group
860
+ class Hatena::Group
861
+ def initialize(name, tag_p)
862
+ @name = name[2..-1]
863
+ @tag_p = tag_p
864
+ end
865
+
866
+ def convert(mode)
867
+ uri = 'http://%s.g.hatena.ne.jp/' % @name
868
+ return uri unless @tag_p
869
+ template=nil
870
+ if mode == :CHTML
871
+ template = '<A HREF="%s">g:%s</A>'
872
+ else
873
+ template = '<a href="%s">g:%s</a>'
874
+ end
875
+ sprintf(template, uri, @name)
876
+ end
877
+ end
878
+
879
+ # Link to Hatena keyword
880
+ class Hatena::Keyword
881
+ def initialize(group, str, tag_p)
882
+ @group = if group then
883
+ Hatena::Group.new(group, false).convert(nil)
884
+ else
885
+ 'http://d.hatena.ne.jp/'
886
+ end
887
+ @str = str
888
+ @tag_p = tag_p
889
+ end
890
+
891
+ def convert(mode)
892
+ uri = '%skeyword/%s' % [@group, URI.escape(@str, /[^-_.!~*'()a-zA-Z0-9]/)]
893
+ return uri unless @tag_p
894
+ template=nil
895
+ if mode == :CHTML
896
+ template = '<A HREF="%s">%s</A>'
897
+ else
898
+ template = '<a href="%s" class="keyword">%s</a>'
899
+ end
900
+ sprintf(template, uri, @str)
901
+ end
902
+ end
903
+
904
+ # Link to Hatena hosted diary
905
+ class Hatena::ID
906
+ def initialize(type, str, tag_p)
907
+ @type = type || 'd'
908
+ @str = type ? type + ":id:" + str : 'id:' + str
909
+ @name, @date = *str.split(/:/,2)
910
+ @tag_p = tag_p
911
+ end
912
+
913
+ def convert(mode)
914
+ uri = case @type
915
+ when /\Ag/ then
916
+ Hatena::Group.new(@type, false).convert(mode)
917
+ when 'a', 'd' then
918
+ 'http://%s.hatena.ne.jp/' % @type
919
+ end
920
+ uri << @name << '/'
921
+ uri << @date if @date &&! @date.empty?
922
+ return uri unless @tag_p
923
+ template=nil
924
+ if mode == :CHTML
925
+ template = '<A HREF="%s">%s</A>'
926
+ else
927
+ template = '<a href="%s">%s</a>'
928
+ end
929
+ sprintf(template, uri, @str)
930
+ end
931
+ end
932
+
933
+ # ISBN & ASIN
934
+ # amazon.rb is required
935
+ class Hatena::Amazon
936
+ def initialize(str, tag_p)
937
+ @str = str.split(/:/)[0]
938
+ @tag_p = tag_p
939
+ end
940
+
941
+ def convert(mode)
942
+ if @tag_p
943
+ sprintf('<%%=isbn_image "%s", "isbn:%s"%%>', @str, @str.delete('-')) # %=
944
+ else
945
+ sprintf('http://www.amazon.co.jp/exec/obidos/ASIN/%s/%s',
946
+ @str,
947
+ Hatena.conf['amazon.aid'] || '')
948
+ end
949
+ end
950
+ end
951
+
952
+ # Amazon search
953
+ # http://d.hatena.ne.jp/hatenadiary/20040310#1078879113
954
+ class Hatena::AmazonSearch
955
+ def initialize(str, tag_p)
956
+ @str = str
957
+ @tag_p = tag_p
958
+ end
959
+
960
+ def convert(mode)
961
+ uri = 'http://www.amazon.co.jp/exec/obidos/external-search?mode=blended&amp;tag=%s&amp;encoding-string-jp=%%c6%%fc%%cb%%dc%%b8%%ec&amp;keyword=%s' % [Hatena.conf['amazon.aid'] || '', URI.escape(@str, /[^-_.!~*'()a-zA-Z0-9]/)]
962
+ return uri unless @tag_p
963
+ template=nil
964
+ if mode == :CHTML
965
+ template = '<A HREF="%s">amazon:%s</A>'
966
+ else
967
+ template = '<a href="%s">amazon:%s</a>'
968
+ end
969
+ sprintf(template, uri, @str)
970
+ end
971
+ end
972
+
973
+ # TeX expressoin
974
+ # texdiary http://kumamushi.org/~k/texdiary/ required
975
+ class Hatena::TeX
976
+ def initialize(expr)
977
+ @expr
978
+ end
979
+
980
+ def convert(mode)
981
+ sprintf('<%%=eq "%s"%%>' % @expr) #%=
982
+ end
983
+ end
984
+
985
+ # String that can contain keywords
986
+ # String that cannot contain keywords is a CDATA
987
+ class Hatena::Sentence
988
+ def initialize(str)
989
+ @elems = Array.new
990
+ return if str.nil? || str.empty?
991
+ if false # kw = Hatena::API.keywords.match(str)
992
+ m = Regexp.new(Regexp.quote(kw)).match(str)
993
+ @elems.push Hatena::CDATA.new(m.pre_match)
994
+ @elems.push Hatena::Keyword.new(nil, kw, true)
995
+ @elems.push Hatena::Sentence.new(m.post_match)
996
+ else
997
+ @elems.push Hatena::CDATA.new(str)
998
+ end
999
+ end
1000
+
1001
+ def convert(mode)
1002
+ @elems.inject('') {|r, i| r << i.convert(mode) }
1003
+ end
1004
+ end
1005
+
1006
+ # Local Variables:
1007
+ # mode: ruby
1008
+ # code: euc-jp-unix
1009
+ # End:
1010
+
1011
+