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.
- checksums.yaml +7 -0
- data/.gitignore +1 -0
- data/.travis.yml +7 -0
- data/Gemfile +13 -0
- data/Gemfile.lock +35 -0
- data/README.en.md +12 -0
- data/README.md +13 -0
- data/Rakefile +41 -0
- data/doc/en/filter/spambayes.txt +3 -0
- data/doc/en/plugin.txt +1 -0
- data/doc/en/style/hatena.txt +10 -0
- data/doc/en/style/markdown.txt +16 -0
- data/doc/en/util.txt +1 -0
- data/doc/ja/filter/antirefspam.history.txt +59 -0
- data/doc/ja/filter/antirefspam.txt +86 -0
- data/doc/ja/filter/comment_key.ja.html +182 -0
- data/doc/ja/filter/spambayes.txt +3 -0
- data/doc/ja/plugin/add_bookmark.txt +50 -0
- data/doc/ja/plugin/category_to_tag.txt +21 -0
- data/doc/ja/plugin/cocoment.txt +31 -0
- data/doc/ja/plugin/google_adsense.txt +25 -0
- data/doc/ja/plugin/google_analytics.txt +7 -0
- data/doc/ja/plugin/image_detail.txt +69 -0
- data/doc/ja/plugin/image_gps.txt +36 -0
- data/doc/ja/plugin/image_gps2.txt +41 -0
- data/doc/ja/plugin/livedoor_weather.txt +105 -0
- data/doc/ja/plugin/opensearch_ad.txt +16 -0
- data/doc/ja/plugin/section_footer.txt +84 -0
- data/doc/ja/plugin/select_theme.txt +1 -0
- data/doc/ja/plugin.txt +13 -0
- data/doc/ja/style/hatena.txt +10 -0
- data/doc/ja/style/markdown.txt +13 -0
- data/doc/ja/util.txt +12 -0
- data/filter/antirefspam.rb +263 -0
- data/filter/commentkey.rb +29 -0
- data/filter/commentsize.rb +18 -0
- data/filter/hidecomment.rb +13 -0
- data/filter/iplookup.rb +55 -0
- data/filter/plugin/antirefspam.rb +59 -0
- data/filter/plugin/commentkey.rb +58 -0
- data/filter/plugin/commentsize.rb +12 -0
- data/filter/plugin/en/iplookup.rb +9 -0
- data/filter/plugin/en/spambayes.rb +123 -0
- data/filter/plugin/iplookup.rb +39 -0
- data/filter/plugin/ja/antirefspam.rb +91 -0
- data/filter/plugin/ja/commentkey.rb +17 -0
- data/filter/plugin/ja/commentsize.rb +6 -0
- data/filter/plugin/ja/iplookup.rb +9 -0
- data/filter/plugin/ja/spambayes.rb +124 -0
- data/filter/plugin/spambayes.rb +501 -0
- data/filter/plugin/zh/iplookup.rb +9 -0
- data/filter/rblcheck.rb +36 -0
- data/filter/spambayes.rb +535 -0
- data/filter/spamlookup.rb +37 -0
- data/io/dbi_io/ChangeLog +19 -0
- data/io/dbi_io/README.ja +39 -0
- data/io/dbi_io/dbi_io.rb +181 -0
- data/io/dbi_io/plugin/refererDbiIO.rb +76 -0
- data/io/dbi_io/tdiary_table.sql +42 -0
- data/js/appstore.js +109 -0
- data/js/datepicker.js +69 -0
- data/js/editor.js +82 -0
- data/js/flickr.js +157 -0
- data/js/image_ex.js +79 -0
- data/js/jquery.socialbutton.js +842 -0
- data/js/nicovideo.js +17 -0
- data/js/picasa.js +322 -0
- data/js/plugin_checker.js +71 -0
- data/js/prettify/lang-apollo.js +2 -0
- data/js/prettify/lang-clj.js +18 -0
- data/js/prettify/lang-css.js +2 -0
- data/js/prettify/lang-go.js +1 -0
- data/js/prettify/lang-hs.js +2 -0
- data/js/prettify/lang-lisp.js +3 -0
- data/js/prettify/lang-lua.js +2 -0
- data/js/prettify/lang-ml.js +2 -0
- data/js/prettify/lang-n.js +4 -0
- data/js/prettify/lang-proto.js +1 -0
- data/js/prettify/lang-scala.js +2 -0
- data/js/prettify/lang-sql.js +2 -0
- data/js/prettify/lang-tex.js +1 -0
- data/js/prettify/lang-vb.js +2 -0
- data/js/prettify/lang-vhdl.js +3 -0
- data/js/prettify/lang-wiki.js +2 -0
- data/js/prettify/lang-xq.js +3 -0
- data/js/prettify/lang-yaml.js +2 -0
- data/js/prettify/prettify.css +1 -0
- data/js/prettify/prettify.js +28 -0
- data/js/referer.js +17 -0
- data/js/show_and_hide.js +39 -0
- data/js/socialbutton.js +126 -0
- data/js/twitter_anywhere.js +28 -0
- data/js/yahoo_kousei.js +21 -0
- data/lib/bayes/convert.rb +34 -0
- data/lib/bayes.rb +232 -0
- data/lib/exifparser/BUGS +1 -0
- data/lib/exifparser/ChangeLog +169 -0
- data/lib/exifparser/README +15 -0
- data/lib/exifparser/install.rb +1015 -0
- data/lib/exifparser/lib/exifparser/makernote/canon.rb +502 -0
- data/lib/exifparser/lib/exifparser/makernote/fujifilm.rb +415 -0
- data/lib/exifparser/lib/exifparser/makernote/minolta.rb +84 -0
- data/lib/exifparser/lib/exifparser/makernote/mk_nikonflensname.rb +39 -0
- data/lib/exifparser/lib/exifparser/makernote/nikon.rb +267 -0
- data/lib/exifparser/lib/exifparser/makernote/nikon2.rb +581 -0
- data/lib/exifparser/lib/exifparser/makernote/nikonflensname.rb +438 -0
- data/lib/exifparser/lib/exifparser/makernote/olympus.rb +225 -0
- data/lib/exifparser/lib/exifparser/makernote/prove.rb +84 -0
- data/lib/exifparser/lib/exifparser/makernote/sigma.rb +237 -0
- data/lib/exifparser/lib/exifparser/pre-setup.rb +1 -0
- data/lib/exifparser/lib/exifparser/scan.rb +278 -0
- data/lib/exifparser/lib/exifparser/tag.rb +2298 -0
- data/lib/exifparser/lib/exifparser/thumbnail.rb +76 -0
- data/lib/exifparser/lib/exifparser/utils.rb +88 -0
- data/lib/exifparser/lib/exifparser.rb +265 -0
- data/lib/exifparser/sample/exifview.rb +279 -0
- data/lib/tdiary-contrib.rb +19 -0
- data/lib/wgs2tky.rb +93 -0
- data/misc/section_footer2/buzzurl.yaml +6 -0
- data/misc/section_footer2/fc2.yaml +6 -0
- data/misc/section_footer2/ldc.yaml +6 -0
- data/misc/section_footer2/retweet.yaml +7 -0
- data/misc/section_footer2/twitter.yaml +7 -0
- data/misc/section_footer2/yahoo.yaml +6 -0
- data/misc/tdiarygraph/tdiarygraph120x90e.swf +0 -0
- data/misc/tdiarygraph/tdiarygraph125x125e.swf +0 -0
- data/misc/tdiarygraph/tdiarygraph240x180e.swf +0 -0
- data/misc/tdiarygraph/tdiarygraph468x60e.swf +0 -0
- data/misc/tdiarygraph/tdiarygraph728x90e.swf +0 -0
- data/misc/tdiarytimes/tdiarytimes125x125r.swf +0 -0
- data/misc/tdiarytimes/tdiarytimes125x125r7.swf +0 -0
- data/misc/tdiarytimes/tdiarytimes125x125s.swf +0 -0
- data/misc/tdiarytimes/tdiarytimes125x30.swf +0 -0
- data/misc/tdiarytimes/tdiarytimes234x30.swf +0 -0
- data/misc/tdiarytimes/tdiarytimes468x30.swf +0 -0
- data/plugin/add_bookmark.rb +89 -0
- data/plugin/apple_webclip.rb +26 -0
- data/plugin/appstore.rb +47 -0
- data/plugin/bigpresen.rb +86 -0
- data/plugin/bitly.rb +39 -0
- data/plugin/bootstrap-navi.rb +54 -0
- data/plugin/canonical.rb +9 -0
- data/plugin/category_similar.rb +73 -0
- data/plugin/category_to_tag.rb +60 -0
- data/plugin/category_to_tagcloud.rb +172 -0
- data/plugin/cocomment.rb +37 -0
- data/plugin/code-prettify.rb +23 -0
- data/plugin/coderwall.rb +34 -0
- data/plugin/datepicker.rb +28 -0
- data/plugin/day2section.rb +20 -0
- data/plugin/del_footer.rb +111 -0
- data/plugin/description_from_body.rb +23 -0
- data/plugin/development.rb +16 -0
- data/plugin/editor.rb +11 -0
- data/plugin/en/add_bookmark.rb +20 -0
- data/plugin/en/del_footer.rb +10 -0
- data/plugin/en/git-register.rb +3 -0
- data/plugin/en/livedoor_weather.rb +25 -0
- data/plugin/en/microsummary.rb +18 -0
- data/plugin/en/nicovideo.rb +38 -0
- data/plugin/en/openid.rb +8 -0
- data/plugin/en/section_footer.rb +6 -0
- data/plugin/en/section_footer2.rb +3 -0
- data/plugin/en/socialbutton.rb +5 -0
- data/plugin/everytrail.rb +39 -0
- data/plugin/facebook_comments.rb +59 -0
- data/plugin/flickr.rb +209 -0
- data/plugin/gist.rb +16 -0
- data/plugin/git-register.rb +240 -0
- data/plugin/github_badge.rb +27 -0
- data/plugin/github_link.rb +9 -0
- data/plugin/goo_gl.rb +42 -0
- data/plugin/google_adsense.rb +132 -0
- data/plugin/google_analytics.rb +39 -0
- data/plugin/google_map.rb +168 -0
- data/plugin/google_sitemaps.rb +60 -0
- data/plugin/google_webmaster.rb +22 -0
- data/plugin/hatena_bookmark_nocomment.rb +9 -0
- data/plugin/hatena_star.rb +66 -0
- data/plugin/hb_footer.rb +255 -0
- data/plugin/hb_footer4sec.rb +244 -0
- data/plugin/hb_footer4sec_js.rb +30 -0
- data/plugin/hide_comment_form.rb +4 -0
- data/plugin/hide_sidebar_iphone.rb +21 -0
- data/plugin/iddy.rb +81 -0
- data/plugin/image_detail.rb +143 -0
- data/plugin/image_ex.rb +462 -0
- data/plugin/image_gps.rb +128 -0
- data/plugin/inline_wiki.rb +6 -0
- data/plugin/instagr.rb +64 -0
- data/plugin/ja/add_bookmark.rb +20 -0
- data/plugin/ja/del_footer.rb +10 -0
- data/plugin/ja/flickr.rb +62 -0
- data/plugin/ja/git-register.rb +3 -0
- data/plugin/ja/google_sitemaps.rb +35 -0
- data/plugin/ja/livedoor_weather.rb +25 -0
- data/plugin/ja/microsummary.rb +18 -0
- data/plugin/ja/nicovideo.rb +41 -0
- data/plugin/ja/openid.rb +7 -0
- data/plugin/ja/section_footer.rb +6 -0
- data/plugin/ja/section_footer2.rb +4 -0
- data/plugin/ja/socialbutton.rb +6 -0
- data/plugin/jdate.rb +20 -0
- data/plugin/jholiday.rb +16 -0
- data/plugin/jmonth.rb +20 -0
- data/plugin/jquery_ui_theme.rb +55 -0
- data/plugin/jroku.rb +28 -0
- data/plugin/jyear.rb +37 -0
- data/plugin/latlonglab_route.rb +25 -0
- data/plugin/lazy_referer.rb +38 -0
- data/plugin/livedoor_weather.rb +180 -0
- data/plugin/make_link.rb +44 -0
- data/plugin/makerss_category.rb +43 -0
- data/plugin/makerss_comment.rb +35 -0
- data/plugin/microsummary.rb +62 -0
- data/plugin/mm_footer.rb +215 -0
- data/plugin/monthly_autopagerize.rb +67 -0
- data/plugin/my_hotentry.rb +132 -0
- data/plugin/navi_day.rb +118 -0
- data/plugin/navi_this_month.rb +15 -0
- data/plugin/nicovideo.rb +115 -0
- data/plugin/notify_miniblog.rb +134 -0
- data/plugin/ogp.rb +55 -0
- data/plugin/ohmsha_estore.rb +71 -0
- data/plugin/openid.rb +90 -0
- data/plugin/opensearch_ad.rb +33 -0
- data/plugin/picasa.rb +56 -0
- data/plugin/plugin_checker.rb +41 -0
- data/plugin/popit.rb +22 -0
- data/plugin/prettify.rb +19 -0
- data/plugin/prezi.rb +10 -0
- data/plugin/profile.rb +222 -0
- data/plugin/puboo.rb +93 -0
- data/plugin/pygments_css.rb +76 -0
- data/plugin/rating.rb +419 -0
- data/plugin/recent_estraier.rb +50 -0
- data/plugin/recent_tweet.rb +71 -0
- data/plugin/retweet.rb +86 -0
- data/plugin/rubykaigi.rb +99 -0
- data/plugin/search-bing.rb +87 -0
- data/plugin/search-default.rb +264 -0
- data/plugin/search-google-custom.rb +60 -0
- data/plugin/search-yahoo-websearch.rb +121 -0
- data/plugin/search-yahoo.rb +109 -0
- data/plugin/section_footer.rb +195 -0
- data/plugin/section_footer2.rb +278 -0
- data/plugin/section_permalink.rb +73 -0
- data/plugin/section_permalink_anchor.rb +39 -0
- data/plugin/select_style.rb +42 -0
- data/plugin/select_theme.rb +90 -0
- data/plugin/show_and_hide.rb +77 -0
- data/plugin/slideshare.rb +10 -0
- data/plugin/socialbutton.rb +60 -0
- data/plugin/tatsu_zine.rb +93 -0
- data/plugin/tdiarygraph_flashstyle.rb +296 -0
- data/plugin/tdiarytimes.rb +166 -0
- data/plugin/tdiarytimes2.rb +406 -0
- data/plugin/tdiarytimes_flashstyle.rb +263 -0
- data/plugin/tdiarytimes_textstyle.rb +290 -0
- data/plugin/title_anchor.rb +16 -0
- data/plugin/tweet_quote.rb +106 -0
- data/plugin/twitpic.rb +10 -0
- data/plugin/twitter.rb +46 -0
- data/plugin/twitter_anywhere.rb +209 -0
- data/plugin/twitter_badge.rb +42 -0
- data/plugin/twitter_js.rb +59 -0
- data/plugin/ustream.rb +19 -0
- data/plugin/vimeo.rb +14 -0
- data/plugin/volatile.rb +89 -0
- data/plugin/vote.rb +100 -0
- data/plugin/wikiloc.rb +27 -0
- data/plugin/windex.rb +512 -0
- data/plugin/yahoo_kousei.rb +79 -0
- data/plugin/yahoo_map.rb +97 -0
- data/plugin/youtube.rb +33 -0
- data/plugin/yshop.rb +189 -0
- data/plugin/zenback.rb +46 -0
- data/spec/apple_webclip_spec.rb +46 -0
- data/spec/fixtures/friendfeed.xml +2 -0
- data/spec/fixtures/github.json +1 -0
- data/spec/fixtures/twitter.xml +73 -0
- data/spec/gist_spec.rb +16 -0
- data/spec/github_link_spec.rb +39 -0
- data/spec/google_analytics_spec.rb +60 -0
- data/spec/jdate_spec.rb +23 -0
- data/spec/jmonth_spec.rb +28 -0
- data/spec/jyear_spec.rb +21 -0
- data/spec/my_hotentry_spec.rb +78 -0
- data/spec/openid_spec.rb +246 -0
- data/spec/opensearch_ad_spec.rb +50 -0
- data/spec/profile_spec.rb +88 -0
- data/spec/rcov.opts +2 -0
- data/spec/spec_helper.rb +223 -0
- data/spec/title_anchor_spec.rb +39 -0
- data/spec/twitter_js_spec.rb +116 -0
- data/spec/youtube_spec.rb +20 -0
- data/style/hatena_style.rb +1011 -0
- data/style/markdown_style.rb +239 -0
- data/style/wikiext_style.rb +21 -0
- data/tdiary-contrib.gemspec +25 -0
- data/util/clean-spam/README.ja +1 -0
- data/util/clean-spam/tdiary-comment-clean +46 -0
- data/util/clean-spam/tdiary-comment-clean2 +81 -0
- data/util/clean-spam/tdiary-referer-clean +46 -0
- data/util/convert_pstore.rb +82 -0
- data/util/estraier-search/ChangeLog +36 -0
- data/util/estraier-search/README.ja +114 -0
- data/util/estraier-search/en/estraier-register.rb +3 -0
- data/util/estraier-search/estraier-register.rb +298 -0
- data/util/estraier-search/estraier-search.rb +273 -0
- data/util/estraier-search/estraier.rhtml +73 -0
- data/util/estraier-search/estraier.rxml +23 -0
- data/util/estraier-search/i.estraier.rhtml +31 -0
- data/util/estraier-search/ja/estraier-register.rb +3 -0
- data/util/image-gallery/README.ja +27 -0
- data/util/image-gallery/image-gallery.rb +523 -0
- data/util/image-gallery/image-gallery.rb.euc-jp +523 -0
- data/util/image-gallery/js/SmoothGallery/Changelog +52 -0
- data/util/image-gallery/js/SmoothGallery/css/ReMooz.css +186 -0
- data/util/image-gallery/js/SmoothGallery/css/img/carrow1.gif +0 -0
- data/util/image-gallery/js/SmoothGallery/css/img/carrow2.gif +0 -0
- data/util/image-gallery/js/SmoothGallery/css/img/closebox.gif +0 -0
- data/util/image-gallery/js/SmoothGallery/css/img/closebox.png +0 -0
- data/util/image-gallery/js/SmoothGallery/css/img/fleche1.gif +0 -0
- data/util/image-gallery/js/SmoothGallery/css/img/fleche1.png +0 -0
- data/util/image-gallery/js/SmoothGallery/css/img/fleche2.gif +0 -0
- data/util/image-gallery/js/SmoothGallery/css/img/fleche2.png +0 -0
- data/util/image-gallery/js/SmoothGallery/css/img/loading-bar-black.gif +0 -0
- data/util/image-gallery/js/SmoothGallery/css/img/open.gif +0 -0
- data/util/image-gallery/js/SmoothGallery/css/img/open.png +0 -0
- data/util/image-gallery/js/SmoothGallery/css/img/remo_bg_e.png +0 -0
- data/util/image-gallery/js/SmoothGallery/css/img/remo_bg_n.png +0 -0
- data/util/image-gallery/js/SmoothGallery/css/img/remo_bg_ne.png +0 -0
- data/util/image-gallery/js/SmoothGallery/css/img/remo_bg_nw.png +0 -0
- data/util/image-gallery/js/SmoothGallery/css/img/remo_bg_s.png +0 -0
- data/util/image-gallery/js/SmoothGallery/css/img/remo_bg_se.png +0 -0
- data/util/image-gallery/js/SmoothGallery/css/img/remo_bg_sw.png +0 -0
- data/util/image-gallery/js/SmoothGallery/css/img/remo_bg_w.png +0 -0
- data/util/image-gallery/js/SmoothGallery/css/img/spinner.gif +0 -0
- data/util/image-gallery/js/SmoothGallery/css/jd.gallery.css +371 -0
- data/util/image-gallery/js/SmoothGallery/css/layout.css +91 -0
- data/util/image-gallery/js/SmoothGallery/license.txt +621 -0
- data/util/image-gallery/js/SmoothGallery/resizer.php +113 -0
- data/util/image-gallery/js/SmoothGallery/scripts/Changelog +52 -0
- data/util/image-gallery/js/SmoothGallery/scripts/History.Routing.js +126 -0
- data/util/image-gallery/js/SmoothGallery/scripts/History.js +109 -0
- data/util/image-gallery/js/SmoothGallery/scripts/ReMooz.js +364 -0
- data/util/image-gallery/js/SmoothGallery/scripts/jd.gallery.js +843 -0
- data/util/image-gallery/js/SmoothGallery/scripts/jd.gallery.set.js +183 -0
- data/util/image-gallery/js/SmoothGallery/scripts/jd.gallery.transitions.js +90 -0
- data/util/image-gallery/js/SmoothGallery/scripts/jdgalleryresize.js +828 -0
- data/util/image-gallery/js/SmoothGallery/scripts/license.txt +621 -0
- data/util/image-gallery/js/SmoothGallery/scripts/mootools-1.2-more.js +103 -0
- data/util/image-gallery/js/SmoothGallery/scripts/mootools-1.2.1-core-yc.js +349 -0
- data/util/image-gallery/js/SmoothGallery/scripts/resizer.php +113 -0
- data/util/image-gallery/misc/plugin/recent_image.rb +406 -0
- data/util/image-gallery/skel/gallery.rhtml +154 -0
- data/util/image-gallery/skel/gallery.rhtml.euc-jp +154 -0
- data/util/image-gallery/tdiary.conf.igsample +8 -0
- data/util/image-gallery/theme/image-gallery.css +85 -0
- data/util/image2flickr.rb +282 -0
- data/util/posttdiary/README.ja +12 -0
- data/util/posttdiary/posttdiary-ex.rb +1155 -0
- data/util/posttdiary/posttdiary.rb +245 -0
- data/util/rast-search/ChangeLog +55 -0
- data/util/rast-search/README.ja +99 -0
- data/util/rast-search/en/rast-register.rb +3 -0
- data/util/rast-search/i.rast.rhtml +33 -0
- data/util/rast-search/ja/rast-register.rb +3 -0
- data/util/rast-search/rast-register.rb +326 -0
- data/util/rast-search/rast-search.rb +249 -0
- data/util/rast-search/rast.rhtml +66 -0
- data/util/rast-search/rast.rxml +21 -0
- data/util/section_link/README +11 -0
- data/util/section_link/misc/plugin/section_link.rb +68 -0
- data/util/section_link/misc/plugin/section_link_anchor.rb +38 -0
- data/util/section_link/tdiary/tdiary_day_ext.rb +21 -0
- data/util/section_link/tdiary/tdiaryext_style.rb +36 -0
- data/util/section_link/tdiary/wikiext_style.rb +36 -0
- data/util/tdiary-for-ruby1.9/compatible.rb +97 -0
- data/util/tdiary-for-ruby1.9/tdiary-2.2.0.patch +98 -0
- data/util/tdiary-for-ruby1.9/tdiary-2.3.1.patch +212 -0
- data/util/tdiary-grep/README +4 -0
- data/util/tdiary-grep/grep.rb +445 -0
- data/util/tdiary-mode/http.el +130 -0
- data/util/tdiary-mode/tdiary-mode.el +613 -0
- data/util/tdiary-vim/ChangeLog +25 -0
- data/util/tdiary-vim/README +60 -0
- data/util/tdiary-vim/tdiary.vim +350 -0
- data/util/tdiarysearch/README.en +53 -0
- data/util/tdiarysearch/README.ja +99 -0
- data/util/tdiarysearch/search.rb +504 -0
- 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&ie=euc-jp&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&tag=%s&encoding-string-jp=%%c6%%fc%%cb%%dc%%b8%%ec&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
|
+
|