はてなキーワード: nilとは
今日は入院している祖母に会いに行く日だ。入院前はもう呆けて風呂も入らないぐらいひどい状態だったが、入院してからはちゃんとしているらしい。
それはそうと、lispでpython環境を構築する話だが、結局オートコンプリートはうざいし、使う機能といったらautopep8とisortぐらいなので、以下を.emacsに組み込んだ。
(defun python-autopep8-and-isort () "Run autopep8 and isort on current Python buffer." (interactive) (when (eq major-mode 'python-mode) (shell-command-on-region (point-min) (point-max) "autopep8 - | isort -" nil t))) (with-eval-after-load 'python (define-key python-mode-map (kbd "C-c C-r") 'python-autopep8-and-isort))
.emacsファイルには他にも様々な設定を付与したが、ここではコードを書ききれない。
さてそういうわけで週末コーディングが趣味としてちゃんと機能することはわかったが、毎週作るとなると、いくつも何かを作るよりは一つのタフなものを作りたいと思うわけである。
それで、最有力候補は「Elasticsearchのようなものをpythonで実装する」という話がある。
Elasticsearchが徹底された設定外部化によってjsonを多用するのだが、これがあまり柔軟性がないので、コードを直にいじれるようにしたいと思ったためである。
例えば自作の日本語トーカナイザを組み込みたいときElasticsearchプラグインをJavaで書かなければならない。私はJavaが嫌いであり、プラグインを「インストールする」という手順も冗長に感じる。
それよりはpythonで作られた検索システムに、適当なトーカナイズ関数を実装して呼び出すことができればかなり柔軟であるように思うわけである。
難しい点があるとすれば、大規模分散システムへの対応で、金をかけなければそういうシステムをテストすることができない。
できるだけ金をかけずに趣味をやるというのがモットーなので、これではまずいわけである。
まあ何事も困難というものはある。まずは手を動かすことが重要だ。Linus Torvaldsも"Talk is cheap, show me the code"と言っているではないか。
https://store.steampowered.com/app/1035760/_Glimmer_in_Mirror/
ENDER LILIES好きな人はハマりそう
https://store.steampowered.com/app/1053900/Radio_the_Universe/
オススメしてもらったやつ。もうPV詐欺でもいいって思えるくらいには虜になった。
https://store.steampowered.com/app/1158160/Coral_Island/
3D版Stardew Valleyと言っても良いくらいには意識してると思う。戦闘要素だけ無い感じ?
https://store.steampowered.com/app/1727210/
演出がHylicsっぽさがあって好き
https://store.steampowered.com/app/1593030/Terra_Nil/
自然再生パズルストラテジー。頭を使いながら視覚的に癒される感じ
https://store.steampowered.com/app/2020630/__Haisonmeguri/
その名の通り。
https://store.steampowered.com/app/1809540/
かなり完成度高めなんだけど発売来年なんだよなぁ…。
https://store.steampowered.com/app/1824580/
https://store.steampowered.com/app/1772830/Rusted_Moss/
ワイヤーアクションメトロイドヴァニア。Twitterのドット界隈で偶然流れてきて知った。
次に続く。 anond:20220629142521
馬鹿に継承を扱わせると、仕事している感を醸し出すために継承を活用せざるを得ない。だから、継承はクソに見える。よって、増田の言いたいことはわかる。
しかし、冒頭で書いたとおり、多態を適切に扱うために継承は必要なのだ。これ以上は書けない。これからもクラスベースの OOP は消えることないであろう。それを書くすべを私は持ち得ていないので、null が消えない事実を例にして語ろうと思う。
21世紀のプログラミング言語のチャレンジの1つはなにか、と言ったら「null 撲滅」であろう。関数型言語は null を排除することに努めたし、Swift 言語は Optional という null がはいっていないことを保証する仕組みを作ったり、Haskell は圏論という数学の概念で応対しようとし、Ruby 言語は &. という「null をスルーするメソッド」を開発した。でも、null は撲滅出来ないままである。
そもそも null とは何か?C言語では、ポインタが指すとそこでお終いだし、Java だとヌルポ(例外)の要因だし、Ruby だと NilClass のインスタンスだし、SQL言語だと「3値論理」では未来のことを記述するためのものだし、言語によって null はバラバラである。つまり、null 自体には特に意味はないのだ。逆に null があると便利だと思わないか?C言語ではポインタに死んでもらえるし、Java だとヌルポがあったら例外にできるし、Ruby だと nil があったらなにかの理由があるからだし、SQL言語だと未来のことは不明と記述できるし。そうなのだ、null はプログラミングに必要なのだ。null をちゃんと扱うのが難しいだけで、null 自体に罪はない。
これを継承、というか多態にあてはめてみよう。多態がないとどうなるか想像してくれ。とてもしんどいことになる。なぜなら...
(作者は眠たくなりました。続きが読みたかったら反応ください。)
たまにRubyでコード書いてるけど、毎回色々と忘れていてつらい。
-a | (number) $1 |
-i- | $1+$2 |
-e- | $1*10^$2 |
-li | $1 (-e- 一番外側) |
-apo- | $1+(point) $2 |
ta- | -$1 |
nil | 0 (任意) |
m | 1 |
d | 2 |
tr | 3 |
ku | 4 |
pet | 5 |
hek | 6 |
siv | 7 |
oct | 8 |
nov | 9 |
tama | -1 |
tapoma | -0.1 |
tametama | -0.1 |
poma | 0.1 |
metama | 0.1 |
pomida | 0.12 |
metamimetada | 0.12 |
trapotrikua | 3.34 |
tritretamikuatada | 3.34 |
siva | 7 |
mema | 10 |
memima | 11 |
dema | 20 |
demida | 22 |
trema | 30 |
kuema | 40 |
meda | 100 |
medimemima | 111 |
deda | 200 |
dedidemida | 222 |
treditremikua | 334 |
ocedimema | 810 |
metra | 1000 |
mekua | 10000 |
mepetimekuikuetripetedimemikua | 114514 |
mehekemiliocta | 1無量大数 = 10^68 |
memeda | 1グーゴル = 10^100 |
metretra | 10^3000 |
mememelida | 1グーゴルプレックス = 10^10^100 |
memememememapolima | ポアンカレ回帰時間 = 10^10^10^10^10^1.1 |
memememememilimetama | ポアンカレ回帰時間 |
結構簡単にできた。
ここから、ページ切り替えてURLを収集する処理も追加すれば、
クローロング部分は完成。
require 'nokogiri'
url = 'http://ja.aliexpress.com/category/200003482/dresses.html?spm=2114.52010108.6.7.gT0qlW&addpid=32546825642&isOnSale=yes%22'
charset = nil
end
doc = Nokogiri::HTML.parse(html, nil, charset)
num=0
doc.css('a[class = "product "]').each do |product|
p product.attribute("href").text
p num = num+1
end
とても嬉しかった。
みなさんのお陰で新たに学んだことと、コメントに対して感じたことをこの日記に残します。
知っていれば賢い、ということでもない。使いこなせない知識は有害
* 外面では見えない知識が表に出て初めて人のお役にたてるかも知れないのに勿体無い限りです。
* 週刊実話を読んだことがありませんので楽しい気持ちになれるなら凹んだ時に読んで見ます。
わたしは無知な女/htmarさん&miyashikiさん
* わたしは無知な女です。
いやいや、確かに知っていても適切に引出から出せないと無駄に思われがちだけど、もしも知っていなかったらそもそも引き出すものがないのだから、やっぱり知っているだけでも価値はあるよ。。/quix_queさん
全知全能になれない以上、全ての存在は何かしらにおいて無知であろう。その中で知ることをやめなければ良いのではなかろうか。/ vidさん
知ることをやめなければ良いのではなかろうか
* めげずに励みます。
知っている方が楽しいことと知っていたほうが悲しいことを天秤にかけたら前者が重たくなるためにはある程度の時期までに蓄積をしなければならないんだとは思う。間に合うのであれば知る努力をしたほうが楽しい/ NOV1975さん
知る努力をしたほうが楽しい
* 知る努力をし、みんなと一緒に楽しいと実感できる日々に向かい現在進行中です。
それでも生きて行けるならそれでいいと思うし、無知を恥じているならそれはものすごい発見でもある。読書ははまると楽しいよ。/ vaginallyさん
無知を恥じているならそれはものすごい発見でもある。
私と比べるから
* 沢山の人達に出会うことで自分の無力さを感じてしまう反面、希望があります。
知らなくていい言葉もいっぱいありますよ。気になるなら週末だけでもコンビニで新聞買ってさらっと見ておくといいかも。/ gohankunさん
いま気付いたのならこれから読めばいいじゃん。まあ知らなければよかったってこともあったりするから、ほどほどでいいのでは。/htnmikiさん
いま気付いたのならこれから読めばいいじゃん。
* 知らなくていい言葉が気になります。「さらっ」「ほどほど」具合が分かりませんので、ついでに体験してみます。
「知らない」ということを知ってるのはだいじ。/K-Onoさんへ
「知らない」ということを知ってるのはだいじ。
* 「知らないことは知らない」ただそれだけのことです。大事であるならば大事だと思うようにします。
上から目線で寛容な理解者ぶりたいおっさんホイホイなのかなと開いたが思った以上に色気がない文章だった/zuiji_zuishoさん
* ガッカリさせてすみません。「色気ある文章」というのが存在するんですね。意識して文章の研究をしてみます。
百聞は一見にしかずって言うよ/QJV97FCrさん
本を読むのって、他人の人生を追体験すること。本を読まない人はやたらと「経験」というけれど、自分ひとりだけの経験と、読書で何百人何千人もの人生の片鱗と知識・知恵を経験した人では見える世界が違うよね。/MK3110さん
読書で何百人何千人もの人生の片鱗と知識・知恵を経験した人では見える世界が違う
* 見える世界…。わたしの世界は良し悪しでも「みんな生きている」というシンプルさです。
どういう成り行きで稲川会を知ったんだ…/nekonekonekotoriさん
* 知らなかったわたしは一先ず安心です。ただ、死ぬ期限が不明です。いずれにせよ人はいつか死にます。念のため、20歳未満の人に忠告しておきますね。
P.Sが本編。/bloominfeelingさん
* P.Sが本編だと困ります。本編に捉えてしまった人がいたということに対して後書きする場合は、どのように表現していいのか考えました。
知ったような口を叩きたくないから、知識を取り入れるようにしてる。/waribashiwaretaさん
* パワーを感じます。
知識を仕入れても大概のことは忘れてるけどね。知らないのと忘れてるの、どっちがいいかわからないけど、仕入れて忘れるのも悪くないなとは思う。/ricemountainさん
* 忘れてもどこかしらに残っていますよね。
*「やったーわたし」ですね。
知ってるつもりより100倍まし/mementm0riさん
* 100倍と明確にされるとは、想定範囲外です。むしろ100倍の威力が気になります。
無知な人がはてな匿名ダイアリーなんて知ってるわけないじゃないですか/junglejungleさん
この増田はまとめ、増田、稲川会を知っている時点で無知じゃない。もっと無知な人間がいる世界だってある/miho3783さん
* わたしは、字を書くのも苦手なためパソコンで日記を書こうとおもい「日記」「無料」「匿名」で検索したらここに辿りつきました。
知っている時点で無知じゃないということは有名なんですね。知れて良かったです。
* 時と場合によっては、使い方があるのではと考えさせられました。
私はムッチリな女、、、 が、親父ギャグ的なものにあたることくらいの知識はある。/ imakimamさん
* 恐縮ですが、ムッチリが無知の言い換えですか?だとしたら、親父ギャグにあたるよりも仕事であてたいです。
「増田」の意味は知ってる?/zeromoon0さん
増田(ますだ)【意味:「はてな匿名ダイアリー」およびその利用者の俗称。当初は「アノニマスダ」「アノニ増田」などと称されていたが、現在ではさらに省略した「増田」が一般的であるようだ。Anonymous Diary(アノニマスダイアリー)に由来する。】
* この日記は文字をクリックしたら辞書へ移動できます。そこで調べた限り、人の名前でした。誰のことかと思い追跡したら上記の意味だったんですね。
* 生活面で悪影響を与えてしまったらすみません。タイトルを変えようと考えましたが他に思い当たる節がないので使わせて頂いています。
小説なんてたくさんある娯楽のうちの一つにすぎないのだから消費しないことを嘆く必要なんてないけど、今後も飯を食っていけるだけの知識と技術を保てるよう専門書をたくさん読むなりして研鑽に励む必要はある/pepekyさん
飯を食っていけるだけの知識と技術を保てるよう専門書をたくさん読むなりして研鑽に励む必要はある
* 専門書という発想がありませんでした。小説と専門書を使いわける選択肢ができました。
知識に人生の逃げ道はない。無学な人間には学がないなりの生き方がある。自分らしさを卑下するのは不健全。口を開けばパズドラと酒と女しか話題がない中卒だからこその野性のたくましさを見習い、笑顔を取り戻せ。/limeclimbさん
知識に人生の逃げ道はない。無学な人間には学がないなりの生き方がある。自分らしさを卑下するのは不健全。
* 無学なりにここまで生きてきました。次は博学なりの生き方をします。
いやー、無知な人ってヤクザの話大好きなんだよ。自分は無知だという自覚が半ば無意識的にあるのだけど、「でも俺はみんなが知らない裏社会のこと知ってるんだぜ」って風に相殺して優越感に浸れるのかもしれない。/Falkyさん
* 学んだことは表に出しなさいと教わりました。
* すみません。「新手の埼玉おっさん案件」を検索したのですが意味が分かりませんでした。井手らっきょかと思い再検索したのですが埼玉ではなく熊本でした。
無知の知。一見無駄かもしれない知識が思いがけない場所で使えることもあるから、色々知ってる人は有利だと思う。/ nil-fellさん
無知の知。「そんなこと知らなくても死なないじゃん」と切り捨てないことは言葉の単語=語彙が多いことよりももっと大切で立派なことだと思うのです。/あと知ったかぶりよりいいよね。と自分に言ってみる/ikd18さん
無知の知と言いますし。/richard_rawさん
* なんだか深いお話です。
知らないというより考えない人が増えている気がする。あるいは、知ってることだけで理解したつもりになって新しい知識を増やす気がない人。算数ができれば数学なんていらないという考え方はこれに近い。/nenashigusanoraさん
* 「知らない」と「考えない」のあいだに壁があるのを感じます。
* 他の方の日記を拝見し、読みやすくできたらと思い記法に辿りつきました。まだまだ使いこなせていません。
本は読んでるつもりだけど稲川会知らない。あと、無知であることを自覚してるならわからないことをどんどん人に聞いてくといいんじゃないかな。その方がコミュニケーション捗るし。/sato-gcさん
* リアル世界とは少々違いますが、今こうしている場もコミュニケーションのひとつですね。
銀河鉄道999より:メーテル「ええ、私は時の流れを旅する女。今までに数え切れないくらい多勢の若者と旅をしてきたわ。ともに喜んでともに悲しんで、そして死に別れてきた。私は一緒に旅した若者のことを決して忘れない。一人一人の思い出をこの胸に刻みこんで抱いて行くわ。永遠に。」
* 共感することもしばしばあります。こんなお話があったんですね。
コメントしてくれた人以外の方も読んでくれてありがとうございます。
「わたしは無知な女」をブックマークする意味が分かりかねます。
ありがたく思います。
また、書きます。
わたしは無知な女。
高野哲というミュージシャンがいることを皆さんはご存知だろうか。
大抵の人は知らないだろう。
別に音楽チャートにランクインだとか、ミュージックステーションに出演とかは
していないから、そんなに知名度は無いと思う。
ただ、彼の作った音楽は嫌というほど聴いたことがあると思う。
絶対に。
よっぽどじゃない限り、聴いたことがあると思う。
ヘキサゴンのめちゃめちゃ耳に残るOPテーマソング「Hate Beat!」
これは高野哲が作った曲だ。
でも、曲は知っていた。
高野哲は元MALICE MIZER初代ボーカルである。
そもそもMALICE MIZERのボーカルだったGACKTの前にボーカルがいた事を
知っている人自体少ない。
なんだ、V系か。
ヘキサゴンのOPテーマを作ったのは元MALICE MIZERの初代ボーカル。
MALICE MIZERがわからない人はグーグルで画像検索をしてくれ。
ここまではOKか。
高野哲はMALICE MIZERというV系のバンドを辞めた後、
もう一度いう、MIXTUREバンドだ。
MIXTUREバンドだ。
そこで彼についてきたV系のファンたちは離れた。
活動に忙しくなったためMega8Ballは休止することになる。
それで高野哲が中心になった3ピースバンドnil(初期)を結成する。
※nilは初期と現在で全く違うバンドになっている。後で説明する。
その後、元ラルク・アン・シエルの櫻澤泰徳がリーダーとなるZIGZOのボーカルとして
迎えられる。
ZIGZOは元ラルク・アン・シエル、元BY-SEXUAL、元MALICE MIZERで構成される、
ロックバンドだ。
もう一度いう、ロックバンドだ。
ここでメジャー・デビューし、HEYHEYHEYなどのTV番組などに出演を果たすも
2枚のアルバムを残し解散する。
ソロで活動することになるが、ソロライブで「あいつらぜってぇ許さねえw」とぼやいたとかぼやかなかったとか。
その後、元SADS、現クロマニヨンズの小林勝、風間が加入し現在のnilになる。
もう一度いう、ロックバンドだ。
nilを勢力的に活動しながら、別バンドTHE JUNEJULYAUGUST(以降ジュンジュラ)を結成する。
2つのバンドを勢力的に活動しながら、ZIGZOを再結成する。
ZIGZOの再結成ライブは2012年3月17日赤坂ブリッツで行われ、プレミアチケットになった。
話がなげーなって思ったそこのおめえ、話はまだ終わっちゃいない。
3つのバンドを勢力的に活動しながら、THEATRE BROOKの佐藤タイジ、うつみようこと
ヘキサゴンのOPテーマを作った元MALICE MIZERの初代ボーカルは
勿論、勢力的に活動を行なっていて、インディーズ電力以外はほぼ
高野哲が作詞、作曲を行なっており、アルバムも何枚も発売していて
それだけ?って思った人挙手!
それだけじゃない、彼が作る曲は彼にしか歌えず、
再販される前はプレミアがついており、シングルCDが2万円だった。
プレミアがついて2万円だった。
==========================================================
昨日書いた上記の内容は書きかけのままアップしてしまったので
追記させてくれ。
そんな作った音楽を誰もが聴いた事があるのに
確認しているだけでもロシア(クロアチア?)、メキシコ、ブラジル、フランス、
台湾、中国、韓国、アメリカ、スウェーデンの国にファンが居る。
不思議だろ?
こよなく愛するファンが海外に沢山いる。
答えはMALICE MIZERを辿ってファンになったそうだ。
でも海外では地道な活動の甲斐あって、広く認知され評価されている。
特にMALICE MIZERは別格で、神格化(言い過ぎかもしれんけど)されているくらいだ。
因みにその高野哲がボーカルとっていた時代のMALICE MIZERのVHSビデオは
プレミアがついている。
映像はギザギザ、カクカクのVHSビデオ、プレミアがついて数万円で
取引されている。
ここまで読んでくれたあなた、薄々高野哲が気になり始めたころじゃないのか?
「もしかして、高野哲というミュージシャンは凄い人なんじゃ?」
高野哲というミュージシャンをミュージシャンが語る時、口を揃えて言うことがある。
==========================================================
再追記させてくだせえ。
ステマ(ステルスマーケティング)じゃないのか?というコメントの件について。
嘘偽りなく正直なところ、俺自身が高野哲というミュージシャンについて語りたかっただけなのだが。
申し訳ない。俺の文才が足りないだけです。
もしステマするならyoutubeの動画のひとつでも貼りたいところ、なのですが。
高野哲というミュージシャンについてはステマは必要がない、としか。
書けば書くほどステマっぽくなっていくのでここらへんで、すみません。
発表しているし、我が強い。
そんなミュージシャンが自分以外の人間を認め、「天才」と評する事自体、
とても不思議な事が起こっている。
この世の中には色んな種類の「天才」がいると思ってる。
また、世間に見出される「天才」と世間の喧騒に埋もれてしまっている「天才」。
作った作品は今も昔も変わらず良いもので、ただ、世間が存在に気づいていないだけ。
ただ、それだけ。
世間が高野哲というミュージシャンに気づいたその時、世界が変わる。
因みに彼(彼ら)はライブでこそ、その真価が見れる。
CDというメディアでは彼(彼ら)の魅力は半分くらいだろうと思う。
こんな人、ごまんといるというコメントについて書くの忘れてた。
ごまんといるかどうか、高野哲が「本物」か「まがい物」か、9月8日に赤坂ブリッツでライブがあるので
自身の目と耳で判断してみてくれ。
その上で、ブログでも、アノニーでも「ごまんといる」やつだったと書けばいい。
ただ、見もせず、聴きもせず、「ごまんといる」とは勿体無いとだけ言っておきたい。
それに、おまいさんは「ごまんといる」やつだったと書かないと思う。
高野哲を見たおまいさんは鼻息荒く帰ってきて「最高だった」というに違いない。
で、youtubeや色んな動画サイトで高野哲の動画を検索するに違いない。
かつての俺がそうだったように。
そして、これを見ているおめえさんは未来の「俺」になっているんだ。
高野哲について語らせてくれってな。
こんなところに、つらつらとな。
聴くのも自由、見るのも自由、またその逆も然り。
これを書いている俺は元々高野哲のファンじゃなかったとだけ、言わせてくれ。
うーん、やっぱりステマかな、これは。
JRuby上で動くRubyとJavaのログを同じファイルに保存したいときなど
JRuby界隈で何かいい方法ないかな~と探していたけど見つからないので
RubyのLoggerのインターフェースをcommons-loggingを使用して実装してみた
使用バージョンは以下
require 'logger' class CommonsLoggingLogger def initialize(name="ruby") @progname = nil @logger = org.apache.commons.logging.LogFactory.getLog(name) end def add(severity, message=nil, progname=@progname, &block) if message.nil? and block_given? message = yield end case severity when Logger::DEBUG debug(progname){message} when Logger::INFO info(progname){message} when Logger::WARN warn(progname){message} when Logger::ERROR error(progname){message} else fatal(progname){message} end end def debug(arg0=nil, &block) @logger.debug make_log(arg0, &block) end def info(arg0=nil, &block) @logger.info make_log(arg0, &block) end def warn(arg0=nil, &block) @logger.warn make_log(arg0, &block) end def error(arg0=nil, &block) @logger.error make_log(arg0, &block) end def fatal(arg0=nil, &block) @logger.fatal make_log(arg0, &block) end def debug? @logger.isDebugEnabled end def info? @logger.isInfoEnabled end def warn? @logger.isWarnEnabled end def error? @logger.isErrorEnabled end def fatal? @logger.isFatalEnabled end def level if debug? Logger::DEBUG elsif info? Logger::INFO elsif warn? Logger::WARN elsif error? Logger::ERROR else Logger::FATAL end end def level=(lv) #do nothing end def sev_threshold level end def sev_threshold=(lv) #do nothing end def datetime_format nil end def datetime_format=(fm) #do nothing end attr_accessor :progname private def make_log(message_or_progname, &block) if block_given? progname = message_or_progname || @progname message = yield else progname = @progname message = message_or_progname end progname_message(progname, message) end def progname_message(progname, message) progname.nil? ? message : "#{progname}: #{message}" end end
これでおしまいだよ
(require 'cl) ; for cl-seq (defvar sangels-movies-dir nil) (defvar sangels-player "c:/Program Files/GRETECH/GomPlayer/GOM.exe") (defvar sangels-sort-by 'sangels-sort-by-rate) (defvar sangels-rate-file "~/.emacs.d/.sangels/rate") (defvar sangels-buffer "*sangels*") (defvar sangels-thumbnail "00_thumbnail.jpg") (defvar sangels-m3u "00_movies.m3u") (defface sangels-name '((t (:family "fixed" :weight bold :height 3.0))) "") (defface sangels-rate '((t (:family "fixed" :weight bold :height 1.5))) "") (defvar sangels-mode-map (let ((map (make-sparse-keymap))) (define-key map "n" 'next-line) (define-key map "p" 'previous-line) (define-key map (kbd "RET") 'sangels-select) (define-key map (kbd "SPC") 'sangels-select) (define-key map "q" 'sangels-quit) (define-key map "+" 'sangels-rate-plus) (define-key map "-" 'sangels-rate-minus) map)) (defvar sangels-mode-hook nil) (defvar sangels-highlight-overlay nil) (defvar sangels-rate-alist nil) (defconst sangels-rate-max 6) (defun sangels-insert-movies () (save-excursion (let* ((inhibit-read-only t) (files (remove-if-not (lambda (x) (and (not (member (file-name-nondirectory x) '("." ".."))) (file-directory-p x) (member sangels-thumbnail (directory-files x)))) (directory-files sangels-movies-dir t))) (ids (mapcar 'file-name-nondirectory files))) (erase-buffer) (setq ids (sangels-sort-ids ids)) (dolist (id ids) (let ((file (expand-file-name id sangels-movies-dir)) (pos (point))) (insert-image-file (expand-file-name sangels-thumbnail file)) (end-of-line) (insert (propertize (format "%-15s " id) 'face 'sangels-name)) (sangels-insert-rate id) (insert "\n") (put-text-property pos (point) 'sangels-id id)))))) (defun sangels-sort-by-name (a b) (string< a b)) (defun sangels-sort-by-rate (a b) (or (> (sangels-rate a) (sangels-rate b)) (sangels-sort-by-name a b))) (defun sangels-sort-ids (ids) (sort ids (or sangels-sort-by 'sangels-sort-by-name))) (defun sangels-insert-rate (id) (let ((rate (sangels-rate id))) (insert (propertize (concat (make-string rate ?★) (make-string (- sangels-rate-max rate) ?☆)) 'sangels-rate t 'face 'sangels-rate)))) (defun sangels-current-id () (get-text-property (point) 'sangels-id)) (defun sangels-play-movie (movie) (let ((explicit-shell-file-name "cmdproxy") (shell-file-name "cmdproxy")) (apply 'call-process-shell-command "start" nil "*tmp*" nil (mapcar (lambda (x) (concat "\"" x "\"")) (list sangels-player (unix-to-dos-filename movie)))))) (defun sangels-select () (interactive) (let ((id (sangels-current-id))) (when id (sangels-play-movie (expand-file-name sangels-m3u (expand-file-name id sangels-movies-dir)))))) (defun sangels-quit () (interactive) (kill-buffer sangels-buffer)) (defun sangels-rate (id) (or (cdr (assoc id sangels-rate-alist)) (/ sangels-rate-max 2))) (defun sangels-rate-save () (interactive) (let ((dir (file-name-directory sangels-rate-file))) (unless (file-exists-p dir) (make-directory dir t))) (with-temp-file sangels-rate-file (insert (pp-to-string sangels-rate-alist)))) (defun sangels-rate-load () (interactive) (when (file-exists-p sangels-rate-file) (with-temp-buffer (insert-file-contents sangels-rate-file) (goto-char (point-min)) (setq sangels-rate-alist (read (current-buffer)))))) (defun sangels-rate-plus (&optional n) (interactive "p") (setq n (or n 1)) (let* ((id (sangels-current-id)) (cell (assoc id sangels-rate-alist))) (unless cell (setq cell (cons id (sangels-rate id))) (setq sangels-rate-alist (cons cell sangels-rate-alist))) (setcdr cell (+ (cdr cell) n)) (save-excursion (let ((inhibit-read-only t)) (beginning-of-line) (goto-char (next-single-property-change (point) 'sangels-rate)) (delete-region (point) (next-single-property-change (point) 'sangels-rate)) (sangels-insert-rate id))) (sangels-rate-save))) (defun sangels-rate-minus (&optional n) (interactive "p") (setq n (or n -1)) (sangels-rate-plus (- n))) (defun sangels-post-command-hook () (save-excursion (move-overlay sangels-highlight-overlay (progn (move-beginning-of-line 1) (point)) (progn (move-end-of-line 1) (forward-line) (point)) (current-buffer)))) (defun sangels-mode () (interactive) (kill-all-local-variables) (use-local-map sangels-mode-map) (setq sangels-highlight-overlay (make-overlay 0 0)) (overlay-put sangels-highlight-overlay 'face 'highlight) (overlay-put sangels-highlight-overlay 'evaporate t) (make-local-variable 'post-command-hook) (add-hook 'post-command-hook 'sangels-post-command-hook nil t) (setq major-mode 'sangels-mode) (setq mode-name "Sangels") (run-mode-hooks 'sangels-mode-hook) (set-buffer-modified-p nil) (setq buffer-read-only t)) (defun sangels (&optional arg) (interactive "P") (when (or arg (not sangels-movies-dir)) (setq sangels-movies-dir (read-directory-name "movies dir: "))) (sangels-rate-load) (switch-to-buffer (get-buffer-create sangels-buffer)) (sangels-insert-movies) (sangels-mode)) (provide 'sangels)
せっかく書いたから匿名でのせてみるよ
使い方は
必要なものを gem で取ってくるにはこうすればいいよ
長すぎてelispが消えたから続きがあるよ
@echo off setlocal set WD=%~dp0 cd /d %WD% ruby get_movies.rb ruby get_images.rb ruby create_m3u.rb
user: ユーザID password: パスワード ids_file: ids.txt done_file: ids_done.txt movies_dir: movies log4r_config: pre_config: global: INFO loggers: - name: app type: Log4r::Logger level: INFO outputters: - STDOUT - FILE outputters: - name: STDOUT type: Log4r::StdoutOutputter formatter: type: Log4r::PatternFormatter pattern: "%d [%l] %C - %M" date_pattern: "%H:%M:%S" - name: FILE type: Log4r::FileOutputter filename: "#{LOGDIR}/sangels.log" formatter: type: Log4r::PatternFormatter pattern: "%d [%l] %C - %M" date_pattern: "%Y-%m-%d %H:%M:%S"
require 'fileutils' require 'logger' require 'mechanize' BASEDIR = File.dirname($0) require "#{BASEDIR}/util" require "#{BASEDIR}/sangels" $config = load_config(BASEDIR) prepare_logger(BASEDIR) $log = new_logger("get_movies") WWW::Mechanize.log = new_logger("mechanize") WGet.log = $log class IDFile def initialize(file) @file = file unless File.exist?(@file) Fileutils.touch(@file) end end def ids(contains_comment = nil) File.open(@file) {|io| io.to_a.map {|x| x.chomp }.select {|x| if x.empty? nil elsif contains_comment true else not /^\s*\#/ =~ x end } } end def add(id) ids = ids(true) unless ids.any? {|x| x == id} write(ids + [id]) end end def delete(id) ids = ids(true) if ids.any? {|x| x == id} write(ids - [id]) end end def write(ids) File.open(@file, "w") {|io| ids.each {|x| io.puts x} } end end $log.info("BEGIN #{$0} ================") exit_code = 0 begin ids_file = IDFile.new($config.ids_file) done_file = IDFile.new($config.done_file) movies_dir = $config.movies_dir wget = WGet.new sangels = SAngels.new sangels.login($config.user, $config.password) ids_file.ids.each {|id| begin movies = sangels.movies(id) rescue SAngels::Movies::InvalidMoviesError $log.warn("invalid movie id: #{id}") next end dir = File.expand_path(id, movies_dir) movies.each {|link| wget.retrieve(link.href, dir) } expected = movies.movie_links.map{|x| File.basename(x.href)} actual = Dir.glob("#{dir}/*").map {|x| File.basename(x)} if (expected - actual).empty? done_file.add(id) ids_file.delete(id) end } rescue => e $log.error(e) exit_code = 1 end $log.info("END #{$0} (#{exit_code}) ================") exit exit_code
require 'fileutils' require 'logger' require 'mechanize' require 'ostruct' BASEDIR = File.dirname($0) require "#{BASEDIR}/util" require "#{BASEDIR}/sangels" $config = load_config(BASEDIR) prepare_logger(BASEDIR) $log = new_logger("get_images") WWW::Mechanize.log = new_logger("mechanize") WGet.log = $log $log.info("BEGIN #{$0} ================") exit_code = 0 begin movies_dir = $config.movies_dir sangels = SAngels.new sangels.login($config.user, $config.password) thumbnails = sangels.thumbnails Dir.glob("#{movies_dir}/*").each {|dir| next unless File.directory? dir id = File.basename(dir) url = thumbnails.url(id) unless url $log.warn("#{id} is not found") next end path = File.expand_path("00_thumbnail#{File.extname(url)}", dir) next if File.exist? path $log.info("retrieving #{url}") thumbnail = thumbnails.get_file(id) File.open(path, "wb") {|io| io.write(thumbnail)} } rescue => e $log.error(e) exit_code = 1 end $log.info("END #{$0} (#{exit_code}) ================") exit exit_code
BASEDIR = File.dirname($0) require "#{BASEDIR}/util" $config = load_config(BASEDIR) movies_dir = $config.movies_dir Dir.glob("#{movies_dir}/*") {|dir| next unless File.directory? dir name = File.basename(dir) files = Dir.glob("#{dir}/*.wmv").sort File.open("#{movies_dir}/#{name}.m3u", "w") {|io| files.each {|file| io.puts "#{name}/#{File.basename(file)}" } } File.open("#{dir}/00_movies.m3u", "w") {|io| files.each {|file| io.puts "#{File.basename(file)}" } } }
require 'mechanize' require 'hpricot' BASEDIR = File.dirname($0) require "#{BASEDIR}/util" class SAngels HOST = "real2.s-angels.com" LOGIN_URL = "http://#{HOST}/member/" INFO_URL = "http://#{HOST}/teigaku/item.php" THUMBNAILS_URL = "http://#{HOST}/teigaku/" THUMBNAIL_URL = "http://#{HOST}/images/default/thumb/" def initialize() @agent = WWW::Mechanize.new end def login(user, password) login_form = @agent.get(LOGIN_URL).forms.find {|form| form.fields.any? {|field| field.name == "frmLoginid"} } login_form.frmLoginid = user login_form.frmPw = password @agent.submit(login_form) end def movies(id, no_validate = nil) Movies.new(@agent, id, !no_validate) end def thumbnails Thumbnails.new(@agent) end class Thumbnails def initialize(agent) @agent = agent doc = Hpricot(@agent.get_file(THUMBNAILS_URL)) elems = doc.search("div[@class=realthum]/a") @links = Hash( elems.map {|elem| href = elem["href"] id = $1 if /ID=(.+)/ =~ href url = elem.search("img")[0]["src"] [id, url] }) end def get_file(id) @agent.get_file(url(id)) end def url(id) @links[id] end def exist?(id) url(id) end end class Movies class InvalidMoviesError < StandardError end def initialize(agent, id, no_validate) @agent = agent @id = id if !no_validate && !valid? raise InvalidMoviesError end end def info_page_url "#{INFO_URL}?ID=#{@id}" end def info_page @agent.get(info_page_url) end def movies_page @agent.click(info_page.links.find {|link| /P=10/ =~ link.href}) end def movie_links movies_page.links.select {|link| /wmv$/ =~ link.href }.sort {|a, b| File.basename(a.href) <=> File.basename(b.href) } end def valid? info_page.uri.to_s == info_page_url end def each(&block) orig_links = movie_links orig_links.each {|orig_link| link = movie_links.find {|l| File.basename(l.href) == File.basename(orig_link.href)} block.call(link) } end end end
require 'log4r' require 'log4r/yamlconfigurator' require 'singleton' require 'fileutils' require 'ostruct' def Hash(a) Hash[*a.flatten] end def load_config(basedir) OpenStruct.new(File.open("#{basedir}/config.yaml") {|io| YAML.load(io)}) end def new_logger(name) Log4r::Logger.new("app::#{name}") end def prepare_logger(basedir, logdir = nil) logdir ||= basedir Log4r::YamlConfigurator["LOGDIR"] = logdir Log4r::YamlConfigurator.load_yaml_file("#{basedir}/config.yaml") end class NullObject include Singleton def method_missing(message, *arg) NullObject.singleton end end class WGet class << self attr_accessor :log def initialize super @log = NullObject.singleton end end def log self.class.log end def retrieve(url, dir) FileUtils.mkdir_p(dir) file = File.expand_path(File.basename(url), dir) if File.exist?(file) log.info("already retrieved #{url}") return true end tmp = "#{file}.part" log.info("retrieving #{url}") ret = system("wget", "-c", "-O", tmp, url) if ret log.info("retrieving succeeded #{url}") File.rename(tmp, file) else if $? == 0x020000 # Ctrl-C exit($?) else log.error("retrieving failure #{url} (#{$?})") end end return ret end end
もちろん、反論もあるだろう。たとえば「Defending PHP」とか。
でも、個人的にはやはり否定側の方が筋が通ってる印象かな。
特に「rubyは初心者に学びやすい(と言われていることが問題である)」という部分に共感する。 rubyは初心者に簡単かもしれないが、初心者による手を抜いたWebアプリケーションは rubyが作られた当初はともかく、現代では害悪ではないだろうか。
cgi.rbならではの理由がないわけではないことはわかる。標準添付されているとか、デプロイが簡単とか。
でも、「標準添付」を一般公開されるWebアプリケーションを開発するためのライブラリとしての利点にするのはもうやめようよ。
追記
「どのライブラリで書いてもおかしなコードを書く奴は書く」という指摘もあった。それは言うまでもない事実ではある。そこには反論しない。
が、本当に問題なのは、世の中には「おかしなコードを書くことを助長するライブラリ」もあるという点だ。で、そういうライブラリにはおおむね「標準添付」というラベルがついている。どういうわけだか。
たぶん、「初心者がおかしなコードを書くのをじゃましない」とかあるいは「初心者っぽいコードを積極的に支援する」から、「標準添付」って呼ばれるんだろう。もしくは「設計者がまだ初心者」とか。
そういうライブラリが存在しちゃいけないとは言わないけど(人に迷惑をかけない範囲で)、ここ半世紀のライブラリの進化をないがしろにするのはもったいないと思うな