tdiary-contrib 3.2.2.20130518

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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
+