仙台Ruby会議02
rubyとビジネスっていうテーマで田舎でビジネスしたり、東京でビジネスする際のいろいろなはなしを聞けて楽しかったです。
いなかにこだわる理由みたいな話で、ずっと優秀な後輩とかと話したいのに東京に行ってしまって寂しいのでなんとかしたい
って話は自分もそう思っている部分があったので、思わずグッと来てしまいました。そのへんツボなのでやめてくれというかんじで(しかも泣けるという)。
それで、商品の本を貰ってしまったので、オレ言語のライブラリ構築のために参考にしようと思います。
あと、サイン貰ったんだけど、1人だけ名のでって話をしてて、ほかの人は北海道に来て貰ってくださいといわれたのでなにかの機会があれば、
北海道に行ってサイン貰おうと思います。
というこういう状況を打破しないと非常によくないので、すこしまともな服を買おうかなと思った今日この頃です。
あと、できるだけどうでもいいような日常的話題を楽しく話す技術を身に着けようと思いました。
ということで、Rubyでの自分のネタっていうとRuby風言語を作って発表とか思ってたのだけど、
時間とやる気がなかった、(たぶん特にやる気のほう)
class Object def eval(env) self end def _(a,op,b) Exp.new(a,op,b) end end class Exp def initialize(a,op,b) @a = a @op = op @b = b end def eval(env) if (@a == :self) then env.send(@op, @b.eval(env)) else env.instance_variable_get(@a).send(@op,@b.eval(env)) end end end class A def p(s) print s end end p binding @a = A.new _(:self, :p, "hello").eval(self) _(:@a, :p, "hello").eval(self)
こんなコードを書いていて終わってしまってました。
何やりたかったかというと、構文木オブジェクトを作って、evalしてやると動くぜー。
っていう感じの仕組みを作ってオレ言語を構文木に変換、実行、イエイ!!ってやつだったんですけど。
でも、RubyはJavaやらPHPといっしょで、メソッドと変数メンバの空間が別ってのを実装するところで止まって終わってました。
たぶん、気力あるときに1日あればそれっぽくバグのあるやつが作れると思うのだけど、そこらへんの理解が足りないので2、3ヶ月いやもっとそれ以上
な感じになってました。
今日はなしたこと
1.スカイプみたいなので駄弁るシステム上でイングリッシュボックスいうのを作って、
話した英語はドラゴントークだかなんだかみたいなので、自動的にテキスト化され、翻訳されて、なんちゃって日本語に変換されて聞けたり、
逆に日本語で話すとドラゴントークみたいなのでやっぱり、テキスト化され翻訳されて、なんちゃって英語になって聞けたりしたら良いんだろうねと。
オレは、別にシステム化する必要はないと思うんだけど、誰か作ったらきっと楽しいんじゃないかと。たぶん使い物にはならないと思うけど。
使い方によっては使えるのではないかと。
2.仙台というか東北にひとつRubyな面白い技術会社が欲しいなと。思い付きじゃなくて願望ですけど。
3.Railsのフィルターの仕組みはきっと全部やってしまうので、効率よくない場面もありそうだから、何とかきれいだけど高速にしてほしいなということを言葉わるーく話してしまった。すいません。悪気があったわけではないのだけど、なんか、そうなってしまったという。
たぶん、周りに不満が多いのを我慢してるからなのか、性格が悪いのか。。。
とにかく、Rubyは美しいと同時に問題もいろいろあって、その辺をツッこむと面白いけど、難しいので大変だけど話す価値はあると思うのですけどってかんじでした。mod_rubyかなにかのapache上で動くなにかは、たまに再起動をサーバ何台かあるうちの1個を落として、みたいなことをタイミングずらしてやるとかしてるって話を教えてもらったりしてなるほどーっと思いました。よく理解してないのですけど、プロセスが複数に分かれててそれがapache上で常駐しており、適当なメモリ食ったら、処理してないときに再起動かければ、問題ないってことっぽかったです。ゴミっぽいやつは消してってゴミっぽくないやつは残しておくんだけど、超GCが必要なタイミングがあったら、再起動というのであれば、JVM起動しっぱなし超巨大メモリで1分停止とかよりずっといいだろうなぁっと。っというのをD言語のtangoあたりが実装してあって、mod_dみたいなのがapache上であれば、高速でいいのかもなぁっと思いました。
あと、リレーショナルデータベースはテーブルを正規化するのがいいってはなしだけども、最近出てきた、name - valueだかなんかのDBとかは、正規化とかできないけど、どうやったらうまく動くのか見たいな話をしたら、ホントに共通に必要なDBはレプリケーションしてほかは、別DBでやるとかするといいとか教えてもらってなるほどなと思いました。
あと、自分が一番下手でいたいみたいな話がなるほどなぁっと思いました。それは地方では結構難しいことなのかもなぁっと。
ああ、あと、翻訳掲示板とか作ってみたのがあったので、遊んでみてね。っと。
http://labs.s-sd.org/enjpbbs/index.php
これをtwitterとかで翻訳発言とかruby逆引きレシピ見つつ作って見れたらいいのかなと。
イングリッシュボックスの話のシステムの今だとrubyクライアントとかこんなかんじだよなぁっと。
ctwitというrubyで作られたコンソールtwitterクライアントをいじってgoogleapiを呼んでってかんじで。
#!ruby -Ks require 'net/http' require 'rexml/document' require 'time' require 'kconv' require 'json' class Twitter #このクラスのメソッドにはすべて文字列を渡す SERVER='twitter.com' attr_reader :username,:password def initialize @id_array=[] end def login(username,password) @username=username @password=password end def get_timeline(filename) req=Net::HTTP::Get.new("/statuses/#{filename}") req.basic_auth(@username,@password) xml=Net::HTTP.start(SERVER) do |http| resp=http.request(req) raise 'リクエストに失敗' unless resp.code=='200' resp end doc=REXML::Document.new xml.body tls=[] @id_array.clear @id_array<<0 i=0 doc.elements.each('statuses/status') do |stat| output="" output<<"[#{(i+1).to_s}]" stat.elements.each('user/screen_name'){|name| output<<name.text<<":"} stat.elements.each('text'){|text| output<<text.text.tosjis} stat.elements.each('created_at'){|time| output<<" (#{Time.parse(time.text).strftime "%Y/%m/%d(%a) %H:%M:%S"})"} stat.elements.each('id'){|id| @id_array<<id.text} tls<<output i+=1 end tls end def get_timeline_with_count(filename,count=nil) if count==nil then get_timeline(filename) elsif count.to_i>200 then get_timeline("#{filename}?count=200") else get_timeline("#{filename}?count=#{count}") end end def get_direct_message(filename,count) if count.to_i>200 then filename+="?count=200" else filename+="?count=#{count}" end req=Net::HTTP::Get.new "/#{filename}" req.basic_auth @username,@password xml=Net::HTTP.start(SERVER) do |http| resp=http.request req raise 'リクエストに失敗' unless resp.code=='200' resp end i=0 doc=REXML::Document.new xml.body dms=[] doc.elements.each('directmessages/directmessage') do |dmes| output="" output<<"[#{(i+1).to_s}]" dmes.elements.each('sender/name'){|name| output<<'From'<<name.text} dmes.elements.each('recipient/name'){|name| output<<' to '<<name.text<<':'} dmes.elements.each('text'){|text| output<<text.text.tosjis} dmes.elements.each('created_at'){|time| output<<" (#{Time.parse(time.text).strftime "%Y/%m/%d(%a) %H:%M:%S"})"} tls<<output i+=1 end tls end def public_timeline #ログインしなくても使える get_timeline "public_timeline.xml" end def friends_timeline(count=nil) get_timeline_with_count "friends_timeline.xml",count end def user_timeline(username,count=nil) get_timeline_with_count "user_timeline/#{username}.xml",count end def replies(count=nil) get_timeline_with_count "mentions.xml",count end def direct_messages(count=nil) get_direct_message "directmessages.xml",count end def my_messages(count=nil) get_direct_message "directmessages/sent.xml",count end def send_message(user,message) message=message.toutf8 req=Net::HTTP::Post.new "/directmessages/new.xml" req.basic_auth @username,@password submit=URI.escape(message) Net::HTTP.start(SERVER) do |http| resp=http.request(req,"user=#{user}&message=#{message}") raise "リクエストに失敗" unless resp.code=='200' end end def submit(status,repto=nil) status=status.toutf8 submit=URI.escape(status) js = Net::HTTP.get_response(URI.parse("http://ajax.googleapis.com/ajax/services/language/translate?v=1.0&langpair=ja%7Cen&q=" + submit)) decoded = JSON.load(js.body) status = status + decoded["responseData"]["translatedText"] req=Net::HTTP::Post.new "/statuses/update.xml" req.basic_auth(@username,@password) submit=URI.escape(status) Net::HTTP.start(SERVER) do |http| if repto==nil then resp=http.request(req,"status=#{submit}") else repto=repto.to_i resp=http.request(req,"status=#{submit}&in_reply_to_status_id=#{@id_array[repto]}") if 0<repto&&repto<=@id_array.size end raise "リクエストに失敗" unless resp.code=='200' end end def follow(username) req=Net::HTTP::Post.new "/friendships/create/#{username}.xml" req.basic_auth @username,@password Net::HTTP.start(SERVER) do |http| resp=http.request req raise "リクエストに失敗" unless resp.code=='200' end end def remove(username) req=Net::HTTP::Post.new "/friendships/destroy/#{username}.xml" req.basic_auth @username,@password Net::HTTP.start(SERVER) do |http| resp=http.request req raise "リクエストに失敗" unless resp.code=='200' end end def fav(favto) #ふぁぼる favto=favto.to_i unless 0<favto&&favto<=@id_array.size raise "リクエストに失敗" else req=Net::HTTP::Post.new "/favorites/create/#{@id_array[favto]}.xml" req.basic_auth(@username,@password) Net::HTTP.start(SERVER) do |http| resp=http.request req raise "リクエストに失敗" unless resp.code=='200' end end end end class TwitterConsole COMMANDS=['login','friends_timeline','public_timeline','user_timeline','replies','direct_messages','my_messages','send_message','submit','follow','remove','fav','exit','quit'] def initialize @twitter=Twitter.new end def login print 'ユーザー名を入力:' name=gets.chomp! print 'パスワードを入力:' pass=gets.chomp! @twitter.login(name,pass) rescue puts "ログインに失敗しました。" end def friends_timeline if @arg.size>0 then @twitter.friends_timeline(@arg[0]).each{|t| puts t} else @twitter.friends_timeline.each{|t| puts t} end rescue puts "タイムラインの取得に失敗しました。" end def public_timeline @twitter.public_timeline.each{|t| puts t} rescue puts "タイムラインの取得に失敗しました。" end def user_timeline if @arg.size==1 then @twitter.user_timeline(@arg[0]).each{|t| puts t} elsif @arg.size>1 then @twitter.user_timeline(@arg[0],@arg[1]).each{|t| puts t} else puts "引数が足りません。" end rescue puts "タイムラインの取得に失敗しました。" end def replies if @arg.size>0 then @twitter.replies(@arg[0]).each{|t| puts t} else @twitter.replies.each{|t| puts t} end rescue puts "タイムラインの取得に失敗しました。" end def direct_messages if @arg.size>0 then @twitter.direct_messages(@arg[0]).each{|t| puts t} else @twitter.sent_messages.each{|t| puts t} end rescue puts "ダイレクトメッセージの取得に失敗しました。" end def my_messages if @arg.size>0 then @twitter.my_messages(@arg[0]).each{|t| puts t} else @twitter.my_messages.each{|t| puts t} end rescue puts "ダイレクトメッセージの取得に失敗しました。" end def send_message if @arg.size>0 print "入力:" @twitter.send_message(gets,arg[0]) else puts "引数が足りません。" end rescue puts "ダイレクトメッセージの送信に失敗しました。" end def submit if @arg.size>0 print "入力:" @twitter.submit(gets,@arg[0]) else print "入力:" @twitter.submit(gets) end rescue puts "つぶやきの送信に失敗しました。" end def follow if @arg.size>0 then @twitter.follow(@arg[0]) else puts "引数が足りません。" end rescue puts "フォローに失敗しました。" end def remove if @arg.size>0 then @twitter.remove(@arg[0]) else puts "引数が足りません。" end rescue puts "リムーブに失敗しました。" end def fav if @arg.size>0 then @twitter.fav(@arg[0]) else puts "引数が足りません。" end rescue puts "ふぁぼるのに失敗しました。" p $! end def run loop{ print "#{@twitter.username}>" @arg=gets.split(/\s/) match=COMMANDS.grep(/^#{@arg.shift}/) if match.length==0 then puts COMMANDS.join(' ') elsif match.length==1 if match[0]=='exit'||match[0]=='quit' then exit else __send__ match[0] end else puts match.join(' ') end } end end tc=TwitterConsole.new tc.run