はてなキーワード: classとは
せっかく書いたから匿名でのせてみるよ
使い方は
必要なものを 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
どう表現したいか、によるんじゃないかな。
重要なのはあくまでリストだってことであれば、ULでマークアップするのはアリ。各LIの中に情報書き込めばいいんじゃないかな。
ただ、TABLE要素が不適だとも思わないけどね。
たとえば、名前の列と生年月日の列があれば、社員同士を比べてどっちが年上かなどを把握しやすい論理構造になる。TABLEってのは視覚的に把握しやすくなるだけじゃなく、「ここには名前の情報が入る」「ここには生年月日の情報が入る」って定義できるわけで、その点ではhttp://anond.hatelabo.jp/20081002194359で書いてあるULでプロフィールをマークアップするよりも意味のある論理構造になるんじゃないかな。
もちろん、LI要素にclass属性つけて「何の情報か」を付け加えてもいいけれど、単にLI要素の中にテキストで「○年○月○日」と書き込んであっても、それが「生年月日」であるか「入社日」であるかはわからないわけだ。
今更だけど60行で作るPHP用テンプレートエンジンをクラス化した。
<?php class NoSixTemplate{ protected $template_dir = null; protected $template = null; protected $context = array(); function __construct($filename = null, $directory = null){ $this->set_template($filename); $this->set_dir($directory); } function set_template($filename){ $this->template = $filename; } function set_dir($directory){ if(substr($directory, -1) != '/') $directory .= '/'; $this->template_dir = $directory; } function set_data($context_key, $context_data, $overwrite = false){ if(empty($this->context[$context_key]) || $overwrite){ $this->context[$context_key] = $context_data; }else{ if(is_array($context_data) && is_array($this->context[$context_key])){ $this->context[$context_key] = array_merge($this->context[$context_key], $context_data); }else{ $this->context[$context_key] .= $context_data; } } } function reset($context_key = null){ if(is_null($context_key)){ $this->context = array(); }else{ $this->context[$context_key] = null; } } function convert_template(){ $filename = $this->template_dir.$this->template; $cachename = $filename.'.cache'; if(!file_exists($cachename) || filemtime($cachename) < filemtime($filename)){ $s = file_get_contents($filename); $s = $this->convert_string($s); if(is_writable($cachename) || is_writable($this->template_dir)){ file_put_contents($cachename, $s); } } return $cachename; } function convert_string($s) { $s = preg_replace('/^<\?xml/', '<<?php ?>?xml', $s); $s = preg_replace('/#\{(.*?)\}/', '<?php echo $1; ?>', $s); $s = preg_replace('/%\{(.*?)\}/', '<?php echo htmlspecialchars($1,ENT_QUOTES); ?>', $s); return $s; } function display(){ $cache = $this->convert_template(); extract($this->context); include($cache); } } ?>
<?php require_once('NoSixTemplate.php'); $template = new NoSixTemplate('template.php', 'template_directory'); $template->set_data('title', 'Example'); $template->set_data('list', array(10,'<A&B>',NULL)); $template->display(); ?>
1. if/while/for/class 文に : (コロン)が必要
例)
while i<5: i=i+1 print i
python はインデント、改行に意味を持たせることをウリとして開発されたわけで、
ここにはインデントがあり、それに意味を持たせられるのだから、: コロンなど必要なはずがない。
Why are colons required for the if/while/def/class statements?
http://www.python.org/doc/faq/general/#why-are-colons-required-for-the-if-while-def-class-statements
(意訳)ボブ「比べてみろよ?こっち
if a==b print a
と、こっち
if a==b: print a
どっちが読みやすい、スザンヌ?」
スザンヌ「まぁ、2番目のほうが読みやすいわ。」
んなぁことあるかーい!!変わらんわい!!
(追記)ボブ「あとは、英語の文法に似せたってのもあるんだ。」
: (コロン)の後に説明書くにしても10行は書かんだろがーー!!それに、似せたんなら、
if a==b, print a
よく、クラスのメンバ変数を private にして、setter と getter 関数を作れといいますよね。こんな風に。
class Person { private $_name; public function setName($name) { if (empty($name)) { throw new IllegalArgumentException(); } $this->_name = $name; } public function name() { return $this->_name; } }
でも、明らかにバカっぽい!! public なら1行じゃないか!!
誰しも、1度ならず10度ぐらいは考えたことがあると思います。
我々崇高なるプログラマはこんなコードを書くために時間を費やしていいはずがない。
そこで、私はあえて、もう全部 public でいい!と推します。関数も。
上記がメインの理由ですが、他の理由もこねくりだしてみます。
なんでこの関数が private !?
中々便利そうな関数があるじゃないか、と思ったら private ! なんてことが実は結構あります。
(それを正式に使いたいとなったら、パッチを投げて議論を交わし導入されるのを待たなければいけません。)
コードをコミットした人は上級者といっていいプログラミングレベルの人です。
そんな人でも、private にしたほうが意図せず外からアクセスされなくて安心、の理論で、
とりあえず private 関数にしてしまうのです。なぜか?
考えたくないからです。
他から利用されたりすることが完全にないと言い切れるのか、などと悩みたくないからです。
この作業は単純なようでいておそろしく時間がかかります。
ありとあらゆる可能性をつぶしていかなければならないからです。
「あとはコードに直すだけ」
なんて言葉を上級者から聞いたことはありませんか?
彼らにとっては、本当に時間がかかるのはアルゴリズムだったり、このようなコード設計なのです。
このコード設計の時間を短縮できれば彼らの崇高なる脳力を有効活用できるのです。
もう、全部 public にすればいいじゃん!
この private 変数覗きたいんですけど!
確かに、設計上、その変数は他所から覗かれることはない変数でしょう。
でも、デバグ目的だったりで、メンバ変数の値を覗きたい、なんていうことは良くあります。
UnitTest をやっていて、途中経過の値を見たい、なんて実はよくあるんじゃないですか?皆さん。
UnitTest は関数の仕様をテストするもので、途中経過がどんな値であろうか問題ではない?
知るか!!オレが今やりたいのはデバグなんだよ!!
なんて実はよくあるんじゃないですか?皆さん。
そんな時、メンバ変数が private だと、わざわざリフレクションを使ったトリックを使ってアクセスしたりと、
本来必要のない時間の使い方をしちゃったりします。
動作未確認。すんげー冗談半分。
// Hatena Monge Star user script // 2008-07-07 // by masda. (http://anond.hatelabo.jp/20080707043247) // ==UserScript== // @name Hatena Monge Star // @namespace http://anond.hatelabo.jp/20080707043247 // @description Hatena Monge Star // @include http://b.hatena.ne.jp/entry/* // @version 0.3.1 // ==/UserScript== // deriving from [http://d.hatena.ne.jp/Hamachiya2/20080707/HatenaBlackStar2] ver Firefox // [http://f.hatena.ne.jp/hatenacinnamon/20070109001332] // Thx! and CUTE! location.href = 'javascript:(' + function() { (function (w) { if (typeof(w.Ten) == 'undefined') { return; } HatenaBookmarkMongeStar = new Ten.Class({ initialize: function(li, entryTitle) { var comment = ''; var tags = ''; var commentSpans = Ten.DOM.getElementsByTagAndClassName('span', 'comment', li); if (commentSpans.length > 0) { comment = Ten.DOM.scrapeText(commentSpans[0]); } var tagsSpans = Ten.DOM.getElementsByTagAndClassName('span', 'user-tag', li); if (tagsSpans.length > 0) { $A(tagsSpans[0].getElementsByTagName('a')).each(function(a) { tags += '[' + Ten.DOM.scrapeText(a)+ ']'; }); } var title = tags + comment; if (title.length == 0) { var name = Ten.DOM.scrapeText(li.getElementsByTagName('a')[1]); title = name + 'のブックマーク'; } // this.uri = 'http://b.hatena.ne.jp/keyword/' + li.getElementsByTagName('a')[1].href; var u = li.getElementsByTagName('a')[1].href; if (u.indexOf('#') == -1) { this.uri = u + '#_HatenaMongeStar'; } else { this.uri = u + '_HatenaMongeStar'; } this.title = title + ' - ' + entryTitle; this.comment_container = Hatena.Star.EntryLoader.createCommentContainer(); var target = commentSpans[0] || li; target.appendChild(this.comment_container); this.star_container = Hatena.Star.EntryLoader.createStarContainer(); this.star_container.className = 'hatena-star-star-container MongeStarContainer'; target.appendChild(this.star_container); } }); var tryCount = 0; var tryMax = 300; function waitForHatenaStar() { // if (Hatena.Star.EntryLoader.loaded) { // Hatena.Star.EntryLoader.loaded = false; var s = document.getElementsByClassName('hatena-star-add-button'); if (s.length) { Hatena.Star.EntryLoader.loaded = false; Hatena.Star.EntryLoader.loadEntries = function() { var entries = []; var title = Ten.DOM.scrapeText(Ten.DOM.getElementsByTagAndClassName('span', 'title', document.body)[0]); var ul = document.getElementById('bookmarked_user'); if (ul) { $A(ul.getElementsByTagName('li')).each(function(li) { if (li.className != 'more') { entries.push(new HatenaBookmarkMongeStar(li, title)); } }); } return entries; } new Hatena.Star.EntryLoader(); } else { if (++tryCount > tryMax) { setTimeout(waitForHatenaStar, 400); } } } setTimeout(waitForHatenaStar, 500); })(window); }.toString() + ')()'; GM_addStyle(<><![CDATA[ .MongeStarContainer { margin-left: 4px; } .MongeStarContainer .hatena-star-add-button { background-color: #fc6 ! important; } .MongeStarContainer a { text-decoration: none ! important; color: #f80 ! important; font-size: 10px; position: relative; } .MongeStarContainer a:before { content: '毛'; font-size:small; } .MongeStarContainer a .hatena-star-star { filter: alpha(opacity=00); -moz-opacity:0.00; opacity:0.00; position: absolute; top: 0; left: 0; } .MongeStarContainer .hatena-star-inner-count { color: #f90 ! important; } ]]></>);
動いたらいいな-
やっぱりprototype.jsのClass.create?
使った事無いけどスーパークラスのメソッド呼び出しできるんだっけ?
http://iandeth.dyndns.org/mt/ian/archives/000664.html
とか参考に自分で書いたら段々でかくなって、4行が今57行w
やっぱ言語のサポートないと辛いわ。こんなに大変だと思わなかった。
って事で「javascriptの継承方法の決め手」なーい?と聞いてみる。
欲しいのは、多重継承が可能で、オーバーライドした子クラスのメソッドから、簡単にオーバーライドされてる親クラスのメソッド呼びたい。ただし、thisは子クラスのオブジェクトのままで、しかも何段でもチェーンをたどれるように。
それとも、あきらめて、クラス名付きで直接親メソッド呼んだ方が良いのかな。やっぱり。
ま。とりあえずシュミグラマだから趣味に走ってみるけれども。
おれはもうMooseしかつかわねぇ。後にも先にもMooseMooseMooseMooseMoose!!!!!!!!!!!1111111
ってな人の為にいつでもどこでもMooseする。automooseを実装しますた。
package automoose; use strict; use warnings; sub import { strict->import; warnings->import; } package automoose::before; use Moose; no Moose; package automoose::after; use Moose; my @before = keys %automoose::before::; my @after = keys %automoose::after::; my @exports = do { my %u; @u{@before} = (); grep { !exists $u{$_} } @after }; package UNIVERSAL; use Moose; for my $func (@exports) { __PACKAGE__->meta->remove_method($func); __PACKAGE__->meta->add_method($func,sub { my $class = shift; my $auto = $class.'::__auto__'; no warnings 'redefine'; local *Moose::_get_caller = sub { return $class }; Moose->import( { into => $auto } ); my $code = $auto->can($func); $class->meta->add_method($func,sub { shift; goto $code; }); goto $code; }); } 1;
使い方はいたって簡単。useするだけ。
use automoose; my $obj = Foo->new;
いきなりnewが呼べちゃう。
他にも
use automoose; Foo->has( hoge => is => 'rw' ,default => 9999 ); Foo->has( muge => is => 'rw' ,default => 7777 ); print Foo->new->hoge; print Foo->new->muge; Bar->extends('Foo'); print Bar->new->hoge;
ょーかんたん。げーべんり。
しっかしこれ、automooseだけど実装するの結構めんどかったのよ。Moose-0.44をベースに作ったんだけどさ。
Moose内部で使用している$CALLERって変数がレキシカルなもんだから、どうやってそれを外から制御すればいいのかすんごい苦労したわけさね。
で結局importの引数にinto渡してさらにMoose::_get_caller関数を上書き無理矢理ハックしたってわけさ。
でもね。でもね。でもね。ちょっと聞いてよ。
ふと最新のMoose-0.50見てみたらさ、Moose::__CURRY_EXPORTS_FOR_CLASS__なんて関数が定義されてるわけよ。
外から明示的に$CLASSを変更できるインターフェイスなわけよ。おいおいおいおい、勘弁してくれよ。こっちゃ折角苦労してハックしたのにあっさり公式対応するなってばよ。メゲルヨ?ぼく。
まぢめげるよ。めげる。ってかもうめげたよ。もうMooseなんてつかわんね!つかわんね!
Mooseなんて大嫌いだー!
俺はMooooooooooseをやめるぞぉおおおおおおおおお、JOJOぉぉぉおおおおお!!!!11
最近Perl界隈ではMoose、MooseってなんかMooseってのが流行ってるらしい。
自分自身のブログでは、さもずっと前からMoose知ってたかのように振舞うために、増田で先に放出しておく。てへへ。
プログラマ層が限りなく低い増田にこんなこと書いてもだれも見てくれない気はするけど。
初めてのMoose - Mooseのすすめ - はてな#hide-k
meta object protocol について考えてみる - TokuLog 改めChumbyとどきました日記
YappoLogs: Moose のコードを探索して理解を深めた
Mooseってのは結局のところClass::MOPのラッパーみたいなもんだと。
で、Class::MOPってのは何だ?ってことだけど、メタなんとかプログラミング?え?プロトコル?まーどっちでもいい。
よくよく読んでいくとメタなんとかとか大層な名前が付いてるけど、結局のところPerlのpackageそのものの操作をオブジェクティブ扱えるようにしたものみたいだ。
つまりだな、例えばpackageに対して動的に(静的ではなく!)メソッドを追加したい場合、今までなら
package Foo; **Foo::method = sub { return 'hoge'; }; print Foo->method;
のように型グロブに関数のリファレンスを突っ込むということをしなければなかったが
use Class::MOP; my $class = Class::MOP::Class->create('Foo'); $class->add_method('method',sub { return 'hoge'; }); print Foo->method;
みたいな感じでかっこよく追加できるってわけさ。ま、これはほんの一例だけどな。(他にもメソッドを削除したりフックしたり色々できる。その辺は今回省略。)
本来なら「package Foo」とするところを「my $class = Class::MOP::Class->create('Foo');」と書ける。
これの何が良いのかというと、$classというオブジェクト経由でFooパッケージを色々操作できるところにつきる。
型グロブを使用したり「no (warnings|strict)」をしたりパッケージを操作する処理っていうのはPerlのキチャナイ構文が多かったのだが、Class::MOPのおかげでスッキリ綺麗に書けるようになったってこった。
で、次にMooseだが、これは結局のところClass::MOPのパッケージ管理の部分に+αしただけのラッパーだ。
でもその+αってのが結構凄かったりする。
もうこの辺の話はさんざん既出だが、例えばhasという関数を使ってアクセサや型定義が出来たり
package Foo; use Moose; has 'method' => ( is => 'rw', isa => 'Int' , default => '10' ); my $obj = Foo->new; print $obj->method; # 10 $obj->method(50); print $obj->method; # 50 $obj->method('hoge') # Int型じゃないのでエラー
Moose::Roleを使ってRubyのMixinみたいなことができたりする。
でも実はこれらの処理ってのは本当は別に凄くもなんとも無い。
アクセサ生成なんてClass::Accessorがあるし、関数の引数の型チェックなんてのもParams::Validate等昔から存在してるし、Mixinに関してはもともとPerlは多重継承できるので最初からできるし。
じゃあなんでみんなMoose、Moose言ってるのかっていうと、それはやはりClass::MOPの存在が大きいであろう。
綺麗且つ柔軟にパッケージの操作が出来るClass::MOPが土台にあって、今まで別々の役割として存在してきたモジュール達を統合し、よりわかりやすく、より柔軟に、そしてより強力なPerlのオブジェクト指向を構築できるようにした。それがMooseなのだ。
・・・しかし、小生。
Mooseについて調べていくうちに一つ残念に思ったことがある。
オブジェクトにメソッドを追加する機構がないのだ。
オブジェクトにメソッドを追加する、だ。パッケージにではなく、オブジェクトに、だ。
具体例をあげる。
package Foo; use Moose; my $obj = Foo->new; $obj->meta->add_method('hoge', sub { return 'hoge' }); print $obj->hoge; # hoge
ちなみに$obj->metaというのはFooパッケージを管理するClass::MOPへのアクセサだ。
ということは上記の処理はFooに対してhogeというメソッドを追加していることになる。
では次の例。
package Foo; use Moose; my $obj = Foo->new; $obj->meta->add_method('hoge', sub { return 'hoge' }); print $obj->hoge; # hoge my $obj_2 = Foo->new; print $obj_2->hoge; # hoge
$obj_2->hogeが呼べてしまうわけだ。
$obj->metaは結局のところFooパッケージなのだから、そこにメソッドを追加しているので当然の結果である。
$objだけにメソッドを追加することは、Mooseではできないのだ。
非常に残念である。ああ、残念だ。
・・・しかし、小生。
これでもプログラマの端くれである。こんなことでめげていてはMooserを名乗れないのである。(あ、MooserってのはMoose使いの人の俗称ね。今僕が考えたの)
なのでオブジェクトにメソッドを追加できるように拡張して見せよう。
package Foo; use Moose; use Class::Object; my $class_object = Class::Object->can('new'); override new => sub { ref($class_object->(shift))->SUPER::new(@_) }; my $obj = Foo->new; $obj->meta->add_method('hoge', sub { return 'hoge' }); print $obj->hoge; # hoge my $obj_2 = Foo->new; print $obj_2->hoge; # エラー
たった3行追加するだけで実現できる。さすがMoose。
ただし、Class::Objectを利用しているのでFoo->newで返ってくるパッケージがFoo::0といったようにFooではなくなってしまっているのでrefとかでパッケージ名の比較ができなくなってしまう問題が発生する。
でもこれも継承順をいじったりと本気で頑張れば、表向きに見せるパッケージ名をFooすることも可能だろう。
その添削の役目はどこかのハッカーに任せるとして、今日のところはこの辺で終了としたい。
Moooooooooooooose!と叫ぶのが流行ってるみたいなので、もっとも長くMooooooooooooooose!と叫んだ最初の男となるべく下記の処理を残しておく。
length q chdir uc and print chr ord uc q rmdir and do { print chr ord q xor x while $a++ < 0xffffffff } or print chr ord qw q sin q and print chr ord q ne sin and print chr hex length q q shift shmread bless q;
[参考文献]
S2 は、.dicon ファイルで定義をだいぶ簡略化できる。パフォーマンスはどうなんだろう。誰かテストしてくれいw
app.dicon
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE components PUBLIC "-//SEASAR//DTD S2Container 2.4//EN" "http://www.seasar.org/dtd/components24.dtd">
<components namespace="client">
<include path="hello.dicon" />
<component class="org.seasar.guice.Client" />
</components>
hello.dicon
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE components PUBLIC "-//SEASAR//DTD S2Container 2.4//EN"
"http://www.seasar.org/dtd/components24.dtd">
<components initializeOnCreate="false">
<component class="org.seasar.guice.HelloServiceImpl" />
</components>
HelloService.java、HelloServiceImpl.java は、上記 ITPro と内容が同じなので省略。
import org.seasar.framework.container.S2Container;
import org.seasar.framework.container.SingletonS2Container;
import org.seasar.framework.container.factory.S2ContainerFactory;
import com.google.inject.AbstractModule;
import com.google.inject.name.Names;
public class Module extends AbstractModule {
S2Container container = null;
public Module(S2Container container){
this.container = container;
}
@Override
protected void configure() {
bind(S2ContainerFactory.class).annotatedWith(Names.named(container.getPath()));
bind(Client.class).toInstance(SingletonS2Container.getComponent(Client.class));
}
}
private HelloService helloService = null;
public void setHelloService(HelloService helloService) {
this.helloService = helloService;
}
public void execute() {
helloService.sayHello();
}
}
Main.java
import org.seasar.framework.container.S2Container;
import org.seasar.framework.container.factory.SingletonS2ContainerFactory;
import com.google.inject.Guice;
import com.google.inject.Injector;
public class Main {
private static final String PATH = ".\\app.dicon";
public static void main(String[] args) {
SingletonS2ContainerFactory.setConfigPath(PATH);
SingletonS2ContainerFactory.init();
S2Container container = SingletonS2ContainerFactory.getContainer();
Module module = new Module(container);
Injector injector = Guice.createInjector(module);
Client client = injector.getInstance(Client.class);
client.execute();
}
}
実行結果
java -cp ?? org.seasar.guice.Main
2008/05/13 21:19:22 org.seasar.framework.log.Logger info
情報: Running on [ENV]product, [DEPLOY MODE]Normal Mode
Hello, world!
[1] http://anond.hatelabo.jp/20080323175904
と
[2] http://d.hatena.ne.jp/ryozo18/20080324/1206301703
を読んで思ったことを書きます。
[1]の人はお子様ですね。その給料が何のために支払われているのかわかってない。
金もらって働いている自覚が全然ないんだろうな。
[2]の人は、ずばりこのことを言いたいんじゃないかなぁ、と思った。
[1]も、自分でもなさけねーなーと思ってるからこそ匿名で書いているんだろうけど、ちょっと前まで学生で年収が600万になろうかとしているくそ坊主にそんな甘っちょろいことを言われたら、どんな人でもぶちぎれると思う。
僕も同じようなこと考えたことがあるから[1]の気持ちは分かります。
ちなみに、僕のスペックは、入社3年目で年収は[1]には及ばなくもきっちり貰ってる方だと思っている中小企業のプログラマ。入社して早々に大規模プロジェクトに投入されてデスマーチの中を生き残って(?)今日に至る。
大規模プロジェクトといっても下っ端にできる仕事と行ったら仕様書通りのclassを書くくらいしかないわけで、まわりの面白そうな案件をやってる先輩がとってもうらやましかったんですよ。だから、最初の頃は[1]と同じようなことを考えていました。
でも、デスマーチの中で働いてるうちに、なんでこんなつらい思いをしなきゃならないのか、もっと楽にできないのか、とか考えだして、自分の関わっている範囲から少しずつ、品質に責任を持つようになったんですよね。
#デスる原因はいろいろあるとは思いますが、やはりPJに関わっている個人の意識が低いことが原因の一つだと思う
また、何よりもバグを作って大変な目に遭うのは自分だけじゃなくてまわりの先輩やお客さんだということがよくよくわかってくるので、品質をあげるためにより真剣に取り組むようになりました。
そうやって少しずつプロ意識が芽生えてきたわけなんですが、おそらく[1]はまだ、そういった切羽詰まった状況に追いつめられていないんでしょうね。
学生のノリでここまできている。自分のことしか考えていない。責任感、皆無ですよね。
だいたい、2年目にして年収600万ももらってるやつが、
「自分のやりたいことができないんです。転職した方がいいですかね?」
なんて悩んでたとしても、それに本気で答えるやつなんていないですよ。自分の親ですら「好きにすれば」っていいますよ。そんなもん。
勝手にやればいいんですよ。何をぐだぐだいじいじ言ってるのかなぁ。
それから、会社では自分のやりたいことができないウボァー、といっていますが、会社はあなたの知的好奇心を満足させるために年収600万を用意しているわけではないと思うんですよ。600万で、与えたその仕事をきっちりやってくださいと言ってるんじゃないかなぁ。さらには、600万以上の仕事をしてくれるのを期待しまくっているんだと思う。
だから、自分のやりたいことを今いる会社でやりたいんなら、その+αの部分で自分のやりたいことを実現するのが筋ってもんでしょう。
結構な金を貰っときながらあまっちょろいことを口にしている人は、自分が会社の期待に応えているのか見つめ直してみたらいいと思う。プロ意識の低いうちは何してもうまく行かないんじゃないかなーと思います。
Python2.5のときは、新スタイルクラスのインスタンスは辞書のキーとして必ず使用できたけど、Python 2.6ではそういうわけじゃなくなってるぽい。という話。
class TestClass(object): def __init__(self, i_name): self._name = i_name def __eq__(self, i_other): if not isinstance(i_other, TestClass): return False return self._name == i_other._name print 'object.__hash__ = ' + str(object.__hash__) print 'TestClass.__hash__ = ' +str(TestClass.__hash__)
上記のようなコードを実行したら、Python 2.5とPython 2.6で結果が違いました。
Python 2.5の場合の結果。
object.__hash__ = <slot wrapper '__hash__' of 'object' objects> TestClass.__hash__ = <slot wrapper '__hash__' of 'object' objects>
Python 2.6の場合の結果。
object.__hash__ = <slot wrapper '__hash__' of 'object' objects> TestClass.__hash__ = None
Python 2.6だと、objectクラスを継承すると、__hash__がNoneになっちゃってる。このままだと辞書のキーとして使えないね。objectを継承したクラスで__hash__を実装すれば、大丈夫みたい。
「ハッシュ値の計算方法 (2)」というページも参考になりそう。
http://anond.hatelabo.jp/20080302214727
「ネタ」がうまくいかない件は、"\u30cd\u30bf"にしたらうまく行った
とりあえず、Sleipnir2のSeahorseで確認。
// ==UserScript== // @name hatebufilter // @namespace hatebufilter // @description Hatena bookmark filter // @include http://b.hatena.ne.jp/hotentry* // @include http://b.hatena.ne.jp/entrylist* // ==/UserScript== /* 問題点 いまのところなし ・問題が起こりそうなURL http://b.hatena.ne.jp/hotentry?mode=daily&date=20080224 http://b.hatena.ne.jp/hotentry?mode=daily&date=20080218 **/ (function(){ // Hatebu Tag var HatebuTagParentNum = 3; var filters = [ // moconico douga {"tag": "div", "name": "entry", "pattern": "nicovideo\.jp"}, /* // tag of "2ch" {"tag": "a", "name": "tag", "pattern": "2ch", "parentNum": HatebuTagParentNum}, {"tag": "a", "name": "tag", "pattern": "\\*2ch", "parentNum": HatebuTagParentNum}, **/ // 2ch blogs // livedoor {"tag": "div", "name": "entry", "pattern": /http:\/\/blog\.livedoor\.jp\/(insidears|dqnplus)\//}, {"tag": "div", "name": "entry", "pattern": /http:\/\/(guideline|alfalfa|news4vip)\.livedoor\.biz\//}, // fc2 {"tag": "div", "name": "entry", "pattern": /http:\/\/(imihu|urasoku|news23vip|waranote|vipvipblogblog|netanabe|res2ch|kanasoku|tenkomo)\.blog\d+\.fc2\.com\//}, {"tag": "div", "name": "entry", "pattern": /http:\/\/www\.kajisoku\.org\//}, // hatena anonymouse diary {"tag": "div", "name": "entry", "pattern": /http:\/\/anond\.hatelabo\.jp\//}, // tag of "neta" {"tag": "a", "name": "tag", "pattern": "\u30cd\u30bf", "parentNum": HatebuTagParentNum}, {"tag": "a", "name": "tag", "pattern": "\\*\u30cd\u30bf", "parentNum": HatebuTagParentNum}, ]; for (var i = 0; i < filters.length; i++) { var f = filters[i]; filtering(f.tag, f.name, f.pattern, f.parentNum== undefined ? 1 : f.parentNum); } function filtering(tag, name, pattern, parentNodeNum){ var entrylist = document.getElementsByTagName(tag); //print("pattern = " + pattern); for(var idx = entrylist.length - 1; 0 <= idx; idx--){ // for(var idx = 0; idx < entrylist.length - 1; idx++){ if (entrylist[idx].className == name){ if (entrylist[idx].innerHTML.match(pattern)) { var node = entrylist[idx]; var oldNode = null; for (var j = 0; j < parentNodeNum; j++) { oldNode = node; node = node.parentNode; } // print("class = " + oldNode.getAttribute("class")); // print("id = " + oldNode.getAttribute("id")); node.removeChild(oldNode); } } } } })();
public class Main { public static void main( String[] args ) { // ( 5 - 3 ) + 1 Exp exp = new Add(new Sub(new Num(5), new Num(3)), new Num(1)); System.out.println(exp.eval()); } } /** * 抽象クラス */ abstract class Exp { public abstract int eval(); } /** * 足し算 */ class Sub extends Exp { /** 左辺 */ private Exp hidari; /** 右辺 */ private Exp migi; /** * コンストラクタ */ public Sub(Exp hidari, Exp migi){ this.hidari = hidari; this.migi = migi; } /** * 評価 */ @Override public int eval() { return hidari.eval() - migi.eval(); } } /** * 引き算 */ class Add extends Exp { /** 左辺 */ private Exp hidari; /** 右辺 */ private Exp migi; /** * コンストラクタ */ public Add(Exp hidari, Exp migi){ this.hidari = hidari; this.migi = migi; } /** * 評価 */ @Override public int eval() { return hidari.eval() + migi.eval(); } } /** * 数 */ class Num extends Exp { /** * 数 */ private int self; /** * コンストラクタ */ public Num(int self) { this.self = self; } /** * 評価 */ @Override public int eval() { return self; } }
firefoxでしか確認していないけれど、URL、正規表現、XPathで指定できる様にしてみたよ。
// ==UserScript== // @name filter for Hatena::Bookmark // @namespace http://anond.hatelabo.jp/ // @include http://b.hatena.ne.jp/hotentry* // @include http://b.hatena.ne.jp/entrylist* // origin http://anond.hatelabo.jp/20080302214727 // ==/UserScript== (function(){ var itemxpath = "//div[@class='entry']"; function xpathgenURL(url) {return "//div[@class='entry' and descendant::a[starts-with(@href,'"+url+"')]]"} var filters = [ // start with '//' then xpath // moconico douga // {"tag": "div", "name": "entry", "pattern": "nicovideo\.jp"}, "//div[@class='entry' and descendant::a[contains(@href,'nicovideo.jp')]]", /* // tag of "2ch" {"tag": "a", "name": "tag", "pattern": "2ch", "parentNum": HatebuTagParentNum}, {"tag": "a", "name": "tag", "pattern": "\\*2ch", "parentNum": HatebuTagParentNum}, ***/ // start with 'http' then url // 2ch blogs // livedoor // {"tag": "div", "name": "entry", // "pattern": /http:\/\/blog\.livedoor\.jp\/(insidears|dqnplus)\//}, "http://blog.livedoor.jp/insidears/", "http://blog.livedoor.jp/dqnplus/", // {"tag": "div", "name": "entry", // "pattern": /http:\/\/(guideline|alfalfa|news4vip)\.livedoor\.biz\//}, "http://guideline.livedoor.biz/", "http://alfalfa.livedoor.biz/", "http://news4vip.livedoor.biz/", // typeof /regexp/ is function (@firefox) then regexp pattern // fc2 // {"tag": "div", "name": "entry", // "pattern": /http:\/\/(urasoku|news23vip|waranote|vipvipblogblog|netanabe|res2ch|kanasoku|tenkomo)\.blog\d+\.fc2\.com\//}, /http:\/\/(urasoku|news23vip|waranote|vipvipblogblog|netanabe|res2ch|kanasoku|tenkomo)\.blog\d+\.fc2\.com\//, // tag of "neta" // {"tag": "a", "name": "tag", "pattern": "ネタ", "parentNum": HatebuTagParentNum}, "//div[@class='entry' and descendant::a[@class='tag' and string()='ネタ']]", // {"tag": "a", "name": "tag", "pattern": "*ネタ", "parentNum": HatebuTagParentNum}, "//div[@class='entry' and descendant::a[@class='tag' and string()='*ネタ']]", // hatena anonymouse diary // {"tag": "div", "name": "entry", "pattern": /http:\/\/anond\.hatelabo\.jp\//} "http://anond.hatelabo.jp/", ]; for (var i=0; i<filters.length; i++) { var filter = filters[i]; var type = typeof filter; var regexp; var xpath; if (type == "function") { xpath = itemxpath; regexp = filter; } else if (type == "string") { if (filter.match(/^http/)) { xpath = xpathgenURL(filter); } else if (filter.match(/^\/\//)) { xpath = filter; } else { next; } } var removeNodes = document.evaluate(xpath,document,null,XPathResult.UNORDERED_NODE_SNAPSHOT_TYPE,null); for (var j=0; j<removeNodes.snapshotLength; j++) { var node = removeNodes.snapshotItem(j); if (!regexp || node.innerHTML.match(regexp)) { node.parentNode.removeChild(node); } } } })();
ついでに増田版も作ってみたよ。
// ==UserScript== // @name filter for Hatelabo::AnonymousDiary // @namespace http://anond.hatelabo.jp/ // @include http://anond.hatelabo.jp/ // @include http://anond.hatelabo.jp/*?page=* // @exclude http://anond.hatelabo.jp/YourID/* // ==/UserScript== // origin http://anond.hatelabo.jp/20080302214727 (function(){ var itemxpath = "//div[@class='section']"; function xpathgenURL(url) {return "//div[@class='section' and descendant::a[starts-with(@href,'"+url+"')]]"} var filters = [ // start with '//' then xpath "//div[@class='section' and child::h3[starts-with(string(),'■はてなの嫌われ者!')]]", // start with 'http' then url "http://anond.hatelabo.jp/", // typeof /regexp/ is function (@firefox) then regexp pattern /釣り/, ]; for (var i=0; i<filters.length; i++) { var filter = filters[i]; var type = typeof filter; var regexp; var xpath; if (type == "function") { xpath = itemxpath; regexp = filter; } else if (type == "string") { if (filter.match(/^http/)) { xpath = xpathgenURL(filter); } else if (filter.match(/^\/\//)) { xpath = filter; } else { next; } } var removeNodes = document.evaluate(xpath,document,null,XPathResult.UNORDERED_NODE_SNAPSHOT_TYPE,null); for (var j=0; j<removeNodes.snapshotLength; j++) { var node = removeNodes.snapshotItem(j); if (!regexp || node.innerHTML.match(regexp)) { node.parentNode.removeChild(node); } } } })();
http://anond.hatelabo.jp/20080102122736
汎用性を上げてみた。
をはてブのhotentryから削除するgreasemonkey。
Sleipnir2のseahorseでも使える。
// ==UserScript== // @name hatebufilter // @namespace hatebufilter // @description Hatena bookmark filter // @include http://b.hatena.ne.jp/hotentry* // @include http://b.hatena.ne.jp/entrylist* // ==/UserScript== /* 問題点 いまのところなし ・問題が起こりそうなURL http://b.hatena.ne.jp/hotentry?mode=daily&date=20080224 http://b.hatena.ne.jp/hotentry?mode=daily&date=20080218 **/ (function(){ // Hatebu Tag var HatebuTagParentNum = 3; var filters = [ // moconico douga {"tag": "div", "name": "entry", "pattern": "nicovideo\.jp"}, /* // tag of "2ch" {"tag": "a", "name": "tag", "pattern": "2ch", "parentNum": HatebuTagParentNum}, {"tag": "a", "name": "tag", "pattern": "\\*2ch", "parentNum": HatebuTagParentNum}, **/ // 2ch blogs // livedoor {"tag": "div", "name": "entry", "pattern": /http:\/\/blog\.livedoor\.jp\/(insidears|dqnplus)\//}, {"tag": "div", "name": "entry", "pattern": /http:\/\/(guideline|alfalfa|news4vip)\.livedoor\.biz\//}, // fc2 {"tag": "div", "name": "entry", "pattern": /http:\/\/(urasoku|news23vip|waranote|vipvipblogblog|netanabe|res2ch|kanasoku|tenkomo)\.blog\d+\.fc2\.com\//}, // tag of "neta" {"tag": "a", "name": "tag", "pattern": "ネタ", "parentNum": HatebuTagParentNum}, {"tag": "a", "name": "tag", "pattern": "*ネタ", "parentNum": HatebuTagParentNum}, // hatena anonymouse diary {"tag": "div", "name": "entry", "pattern": /http:\/\/anond\.hatelabo\.jp\//} ]; for (var i = 0; i < filters.length; i++) { var f = filters[i]; filtering(f.tag, f.name, f.pattern, f.parentNum== undefined ? 1 : f.parentNum); } function filtering(tag, name, pattern, parentNodeNum){ var entrylist = document.getElementsByTagName(tag); //print("pattern = " + pattern); for(var idx = entrylist.length - 1; 0 <= idx; idx--){ // for(var idx = 0; idx < entrylist.length - 1; idx++){ if (entrylist[idx].className == name){ if (entrylist[idx].innerHTML.match(pattern)) { var node = entrylist[idx]; var oldNode = null; for (var j = 0; j < parentNodeNum; j++) { oldNode = node; node = node.parentNode; } // print("class = " + oldNode.getAttribute("class")); // print("id = " + oldNode.getAttribute("id")); node.removeChild(oldNode); } } } } })();
hatebufilter.user.jsなどとUTF-8で保存して使う。
しかし、増田のコード記法、日本語貼り付けたら化けるんだが・・・どうすればいいんだろ?
コメントアウトを直せば、2chコピペブログ以外の「2ch」タグ自体での削除も可能です。
ついかっとなって書いた。動くことを優先で書いてるので、変なコードあるかも。
参考にしたもの:増田にあぼーん機能を追加するgreasemonkey
// ==UserScript== // @name hatena diary comment filter // @namespace http://anond.hatelabo.jp/ // @description abone specified id's comments. // @include http://d.hatena.ne.jp/* // ==/UserScript== (function(){ var ignore = [/kyoumoe/, /DASM/]; var abonemessage = "abone"; var commentatorIDs = document.evaluate('//a[@class="hatena-id-icon"]', document, null, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null); for (i=0; i < commentatorIDs.snapshotLength; i++) { var commentatorID = commentatorIDs.snapshotItem(i); var idName = commentatorID.textContent; for (j=0; j < ignore.length; j++) { var isIgnoreID = ignore[j].test(idName); if(isIgnoreID) { break; } } if(isIgnoreID) { var commentator = commentatorID.parentNode; while(commentator.firstChild) { commentator.removeChild(commentator.firstChild); } commentator.textContent = abonemessage; var commentBody = commentator.nextSibling.nextSibling.nextSibling.nextSibling; while(commentBody.firstChild) { commentBody.removeChild(commentBody.firstChild); } commentBody.textContent = abonemessage; } } })();
スカシカシパン素敵だけど、
ブンブク目の名前のフリーダムっぷりも気になる。
http://www.neodiving.com/tour/neozukan/sonota/sonota.html#%e3%82%a6%e3%83%8b%e9%a1%9e
以下から必要なファイルをDL。wiki/skinに放り込む。
http://code.google.com/p/google-code-prettify/
<?php if (PKWK_ALLOW_JAVASCRIPT) { ?> <script type="text/javascript" src="skin/prettify.js"></script> <link href="skin/prettify.css" rel="stylesheet" type="text/css"/> <?php } //** SETTING FOR GOOGLE CODE PRETTIFY! **//?>
<body onload="prettyPrint()">
Class Pre extends Element { ... function toString() { return $this->wrap(join("\n", $this->elements), 'pre', ' class="prettyprint"'); } }
define('PKWK_ALLOW_JAVASCRIPT', 1);
なんかデーターが見つからない危険性を感じるというか。ファイルがでかいからreadlinesとか使いたくないんだけれども無理かな。
class Id_sorted_data def initialize path, avarage_bytes_by_one_data, search_margin @f = File.open(path); @v = avarage_bytes_by_one_data; @cash = {}; @margin = search_margin; return self end def read number if @cash.member?(number) return @cash[number]; end @f.seek([(number - @margin) * @v, 0].max); for i in 1..20 @f.readline; temp = @f.readline; @cash[temp.to_i] = temp; if temp.to_i == number return @cash[number]; elsif (number - @margin .. number).include?(temp.to_i) return near(number); end @f.seek((number - temp.to_i - @margin) * (@v * (20 - i) / 20), IO::SEEK_CUR); end end def near number for i in 1..@margin temp = @f.readline; @cash[temp.to_i] = temp; if temp.to_i == number return @cash[number]; end end end end
だいたい、セグメンテーションフォルトを起こすような言語は嫌い
Haskelわけわかんないし
Java重苦しいし、いちいちclass Hogehoge { public static void main() { ... } }書くのがめんどくさいし、API多すぎ
オブジェクト指向したくなるような複雑なプログラムは最初から考えない(作れない)
言語が提供するGUIのツールはOSとは別に独自のレイヤー、世界感を持っててとっつきにくい
マルチスレッド、排他処理を扱うようなプログラムは脳味噌がついて行かないので書かない
Ruby、、、そもそもLL言語で大規模でオブジェクト指向なプログラム書きたくない。小規模ならオブジェクト指向要らない。
俺のマシンで実行できないAda/Basic/Fortran/Pascal その他いろいろ
VHDL、Verilog?FPGAやゲートアレイなんて持ってない、持ちたくない(苦手だもん)
HTML、XMLは日本語とタグが入り乱れるので、そのつど日本語入力の切替えが死ぬほど嫌になった。
だから、HTMLとXMLは全部手入力なんて真似は絶対してやらねえ。
Flex(Action Script)はコンパイラがJavaで実装されてて重すぎる。(シェルを使えばまし)
JavaScriptはブラウザごとの挙動の違いを吸収しきれる自身が無いので使わない。
1プログラムにつき、(コメント含めて)250行以上書きたくない
(本文には触ったこともない言語を思い込みで罵倒しているなど、嘘、おおげさ、紛らわしいが多数混入しています。それが全部わかった貴方はプログラミング言語マスターです。)
いや、本人同士がそれでいいならいいんですけどね、どっちかが長文うぜーなーとか思ってたりする場合も多いわけじゃないですか。ただの野次馬である傍観者にとっては特にそうだと思うんですけど。
はてブに「長い」とかコメントされてるエントリとかを想起していただけるとありがたいんですけど。
どうもそういうのを見るとついついフォード・ピント事件なんかを思い出してしまうわけですよ。
知らない人はググって下さいね。一応映画にもなってたりするんでお暇なら観てみるのもいいんじゃないかとオススメしますですよ、ハイ。(邦題『訴訟』原題『The Class Action』)そんなのめんどくせーよーという人の為には解説してるアドレス貼っときますね。(http://www.fps.chuo-u.ac.jp/~cyberian/Ford_Pinto.html) んでリンク踏むのさえめんどくせーとかacドメインとか読んでもわかんねーよという先入観をお持ちのあなたの為に適当に解説しちゃいますと、フォードが日本車に押され始めた時代にこれじゃいかんってわけでコンパクト・カーを売り出したの、ピントっていう。しかしまぁリーズナブルなだけあって結構売れちゃったりしたんだけども安全設計もリーズナブルだったのが問題になって訴訟起こされちゃいました。
ちなみにアメリカの訴訟制度ってのはなかなか面白いもので、この手の訴訟だとあの有名な懲罰的損害賠償(企業が痛いな、と思う範囲まで賠償金額上げちゃっていいよ制度)と、Class Action 制度(同様の被害を受けた人は先人の訴訟結果にタダ乗り出来ちゃう制度、日本だと訴訟提起後結審前までは参加が許されたんだっけ、詳しくは知らないんでゴメンネ)のおかげで絶対負けられないんよね。
ここら辺はまぁどうでもいいんで次行きますけど、訴訟開始前にディスカバリーって制度があるんですよ。
この手の訴訟の場合被告の企業側に証拠ってあるもんですしね。それを原告側が請求できる制度なんですよ。
といっても原告側もそんなに詳しく企業内事情を知ってるわけじゃあないんで請求内容がある程度曖昧にならざるを得ないわけでね、それを逆手に利用して、被告企業がそれこそ倉庫が一杯になる位の量の内部文書を送りつけるって行動に出るわけです。
そんなことされたら困るよねー。
原告側は何と言っても少数者であるわけだし、精査しようにも人件費が酷いことになっちゃうし、いかんともし難い状況になったよってお話(この先は映画見てね)。
んでこれを最初の話に無理矢理つなげると、長々と文章書いて相手に対応してる人って、誠実に答えてるようでいて実は単に目晦まししてるんじゃないの?って疑問が湧いたよってお話。
2chでよく言われるように3行までしか読めない、ってのは少々極端に過ぎると思うのだけれど、しかしそうそう長い文章を時間コストをかけて読めるわけではないよね、ってところはなんとなく理解してもらえるんじゃないかなぁ。
世の中には楽しい事やしたい事ってのが一杯あって(セックル(恋人とならタダだと思ってても多分風俗の方が安くて気持ちいいよ、次々入れ替わるから新鮮だし)とか食べ歩き(ってよりこんなところで食事してる俺/私って素敵欲望ドライブなんじゃないの)とかもっと寝たい(偽装請負ご苦労様です。所得隠ししなけりゃ設備投資費用も捻出できない世界有数の好景気大企業の下請じゃポイズン)とかデイトレード(まだやってる人いるの?)とか自己啓発(はてなとFPNってこういう腐臭がするよね、どうでもいいけど。Lifehuckだってw)とか宗教儀式(明治天皇の声が聞こえる!!とかグーグルの狂気とか)とかさ)、ネットで議論なんてモノはそのうちの一つでしかないわけだし。
しかもディスプレイとかブログっていうアーキテクチャはほんと長文読むのに適さない環境なんじゃないかとオールドタイプな僕は思ってしまうわけですけども。
A4一枚分以上は紙で読みたい。
こういう人って結構いるんじゃないかなぁと思うわけですよ。
そういう人に対して誠実にあるにはどうしたらいいのかねぇって所はこの発達した世の中でも解決されてないんじゃなかろーか。
これってビジネスチャンス?ニートのボクでも起業してお金持ちになってセックル三昧(ここまでjkondo)、金で女は買えると豪語した挙句に証券取引法違反で国策捜査の上つかまってあれやこれや的展開が期待できるかもーうはーすげー。
あ、ごめん妄想入った。
文章なんてのは長くしようとすればどこまででも長く出来るし、短くしようと思えば結構な割合で短くなるものだと思うんですよ。
お前2時間でいいじゃんみたいな。
ただ、短く書く時には削ぎ落とされた部分を読む側が理解してないといけないという条件は付きますが。
ってことは長々と文章書いてる人ってのは読み手の力量を信用してない、ってことになるんですかね。
まぁはてブ衆愚とかネットイナゴなんてのが流行ってる昨今さもありなんな発想ではあるわけですが、エントリ書く奴が偉くて読み手は衆愚だからこんなことまでわざわざ書いてやらねばならん、みたいな。
そんな目で見ないでお願い。
それならいっそやde√blog終風先生みたいにわからん奴はもういいよ的に放置されるほうがまだマシじゃね? ってか終風先生=紫式部か。
終風日記や極東ブログは省略省略で貴族たり得ない衆愚である受験生を困惑させる源氏物語か。
挙句にシステムスルーカですか、イナゴはイナゴらしくオマニーでも見てればいいですかそうですか。
切ないなぁ、ああ切ない。
大島弓子ばりに切ないよ。
伝われこの思いの8頭身の心境ですよ。
大体あれだ、平野啓一郎もあれだよな、『日触』しか読んだことないけど漢字難しいよな、初手からお前ら文学イナゴは寄ってくんなオーラ全開だよな。
昔の日本文学読んでりゃ理解出来るとか言われてもそりゃ無理っすよ、旧字体で読んでる人っているのかね。
あんなのに造詣が深いのってめっちゃレアモンスターだと思うんですけど。
なんかはてな内には散見されるのが面白いといえば面白いのかもしれないが。
しかしまぁあんな小難しい本読むくらいならあれだね、同じ京大出身でも森見登美彦の方が全然面白いと感じちゃうね。
あ、ここでいう「非モテ」っていうのはある程度の文化資本をもった、顔面や身体に不都合があったり拗れた精神構造持ってる人ね。
(PCなんて気にしねぇ)だってボクの後ろでウメダモチオとかessaがグーグルとか権力論とかビジネスモデルとかを語れない期間工みたいな奴ははてなーではない、って囁いて来るんだもん。ここはてなだし仕方ないよね。
しかしまぁスルーってのも寂しいもんだよね。
皆が皆スルーし合って出来上がる世界ってアレだよね、なんつーかちょっとつまらんよね。
ってかこれって物象化じゃないのか。
マルクスの亡霊は未だ徘徊してるのか。
ごめんちょっと難しい言葉使ってみたかった。
中二病といいたければ言うがいいさ。
でも心の隙間に大阪のおばちゃんを忘れないでいて欲しいなぁと。
さてもう収拾がつかなくなったのでこの辺で終わりにするけど、長文批判のためにはじめたこのエントリがやたら長くなった事を心より詫びる。
どうせスルーされるんだろうなぁ。
Pythonではなぜ string.len() でなく len() なのか?
string = MyString("Hello world")
class String def len self.length end end print "Ruby on Rails".len #=> 13
http://anond.hatelabo.jp/20071021143442
その理由は知らないが、なければ作ればいいじゃないか。
class MyString(str): def length(self): return len(self)
というクラスを作って
string = MyString("Hello world") print string.count("o"), string.length()
とRubyライクにやれば
2 11
とでるよ。え、リストもlist.length()が使いたいって?それも簡単。
class MyList(list): def length(self): return len(self) l = MyList([1, 2, 3, 4, 5, 6]) l.length()
6
きちんと他のメソッドも使えるよ。
l[1:]
[2, 3, 4, 5, 6]
l.reverse() l
[6, 5, 4, 3, 2, 1]
ね。簡単でしょ。
Pythonは仕組みが統一されているものが多いので、いじりやすいのですよ。上の例のやつは組み込みのクラスオブジェクトとユーザー定義のクラスオブジェクトがおおむね統一されているからこそ簡単にできる。他にも関数なんかもほかのオブジェクトと同じオブジェクトなので、高階関数なんてもの簡単に作ることができて関数プログラミングぽくできる。例えば今はなきapply関数なんかは
def myApply(func, *args): return func.__call__(*args)
と定義できる。実際に
def sumUpThree(num1, num2, num3): return num1 + num2 + num3
でためしてみる。
myApply(sumUpThree, 1, 2, 3)
結果はちゃんと
6
とでる。将来廃止されそうなmap関数も簡単に定義できる。他にも複数の引数をもつ関数の部分適用のようなことを行う関数も次のように簡単に定義できる。
def partial(func, *oldArgs): def wrapper(*newArgs): return func.__call__(*(oldArgs + newArgs)) return wrapper
sum_1 = partial(sumUpThree, 1) sum_1(2, 3)
6
sum_1_5 = partial(sum_1, 5) sum_1_5(9)
15
sum_10_20 = partial(sumUpThree, 10, 20) sum_10_20(30)
60
こういう風に高階関数が簡単にできるのは関数がオブジェクトで関数の実行とはメソッドの呼び出しにすぎないからだ。以上のように組み込みオブジェクトとユーザー定義オブジェクトの差があまりないことや関数もオブジェクトであることに見られるようにPythonは仕組みが統一されていてシンプルだ。そのためひとつのことがわかれば他のこともわかることが多いし、簡単にいじることもできる。
だからなければpythonをいじればいいと思うよ。
最後にラムダ式信者のためにpartialをラムダ式を使って書いておく。
def partial(func, *oldArgs): return lambda *newArgs:func.__call__(*(oldArgs + newArgs))