Hatena::Grouprubyist

たばさの RSSフィード

05/31(日) 2009

おせないボタンマジック

おせないボタンマジック - たばさの を含むブックマーク はてなブックマーク - おせないボタンマジック - たばさの

はてブにグラフが出るようになった。

f:id:hatecha:20090531103226j:image

グラフとコメントの位置関係によってマウスを持ってくと消える。残念。スタイルシートを外してコメントした



もどかしい、と思って、えーとなんだっけもどかしい。と、今回はつながりの浅い連想だったので検索してようやくたどり着いた。

http://www.youtube.com/watch?v=kcNfC2bMxwY


ある状況になると必ずこの曲っていうふうに繋がってるよね、頭の中で。音楽じゃなくてもいい。

特に好きな曲ではなくても、UFOという言葉が出てくると必ずピンクレディが流れるとか。

一度繋がるとなかなか切り離せない。


こうやってすぐたどり着けるのも考えようによっては味気ないのかも。

google waveの映像を見た。リアルタイム性。すごいけど実際に大勢でいっせいにひとつの文章を編集する必要性って言うのは思いつかないな。どう使うんだろう。

頭の体操といえば。楽天が悪いというより店舗にメールアドレスを要求されて断れず何年も改善できずうやむやというところに落ち着くかなあと一瞬思うがでも一件10円て言ってるしな。やっぱり商売商売。

自分としては個人情報というか「楽天は言ったこと(店舗にメルアドを渡さないように変えるとかつて言ったこと)を守るのか」に焦点があるのだけどひとそれぞれ焦点が違って見事に噛み合ってない。

トラックバック - http://rubyist.g.hatena.ne.jp/hatecha/20090531

05/29(金) 2009

YQL、SQLぽい構文でhtmlをxmlに変換

| YQL、SQLぽい構文でhtmlをxmlに変換 - たばさの を含むブックマーク はてなブックマーク - YQL、SQLぽい構文でhtmlをxmlに変換 - たばさの

Yahoo! Query Language

no title

使いようによって面白いような。


select * from html where url="http://rubyist.g.hatena.ne.jp/hatecha/archive"
 and xpath='//*[@class="archive archive-section"]'

=>

http://query.yahooapis.com/v1/public/yql?q=select%20*%20from%20html%20where%20url%3D%22http%3A%2F%2Frubyist.g.hatena.ne.jp%2Fhatecha%2Farchive%22%0A%20and%20xpath%3D'%2F%2F*%5B%40class%3D%22archive%20archive-section%22%5D'&format=xml

ブラウザで開くとものによっては固まるような。ブラウザのせい?マウスも調子悪いし。



タイトルだけ表示してみる。使いこなせてないですが。

yql-test.rb

require'xmlsimple'
require'open-uri'
require'pp'
require'kconv'
$data=""
open(ARGV[0]){|f| $data=f.readlines*""}
$persed=XmlSimple.xml_in($data)
xx= $persed["results"][0]["li"]
content=xx.select{|i|i.class==Hash and i.key? "p"}
$cc=content.map{|i|
    c=i["p"][0]["a"][-1]["content"].tosjis
    next if !c
    c.gsub!(/\W+/s){""}
    c
}
$cc.each{|i|puts i}
 > yql-test.rb "http://query.yahooapis.com/v1/public/yql?q=select%20*%20from%20html%20where%20url%3D%22http%3A%2F%2Frubyist.g.hatena.ne.jp%2Fhatecha%2Farchive%22%0A%20and%20xpath%3D'%2F%2F*%5B%40class%3D%22archive%20archive-section%22%5D'&format=xml"

参考

XmlSimple (ruby) を使ってみる - Loud Minority

トラックバック - http://rubyist.g.hatena.ne.jp/hatecha/20090529

05/28(木) 2009

gcalapi

| gcalapi - たばさの を含むブックマーク はてなブックマーク - gcalapi - たばさの

exampleのmixi2gcal.rbを使ってみた。

*1


動かないところを修正。

tableはひとつになっている。

table = (root/"table")

空の要素があるので飛ばす。

  f = td.children[0]
  next if !f

あとは

http://doruby.kbmj.com/trinityt_on_rails/20081022/Ruby_Google_

をみてcalendarのurlを変える。

delete allなどとあるが削除はしたくないのでコメントアウトしておく。

できたー



mixiのところを消して

 result=[
   {:day=>"1",:desc=>"event1"},
   {:day=>"2",:desc=>"event2"},
   {:day=>"3",:desc=>"event3"}
]

などとやればカレンダーに追加だけできる。

と思ったけどinner_textとかあるからもうちょっといじらないとだめだな。



と、OAuth,AuthSubなど検索してるんだけど

これはAuthSubは関係ないな?

*1:おっと作者はこちらのようです、またはてなか。 http://d.hatena.ne.jp/zorio/20070204/1170560623

トラックバック - http://rubyist.g.hatena.ne.jp/hatecha/20090528

05/26(火) 2009

いつのまにやら容量が

| いつのまにやら容量が - たばさの を含むブックマーク はてなブックマーク - いつのまにやら容量が - たばさの

windowsXPのntfs上にinstallした)ubuntuが14G使ってる。ubuntu普段はあまり使ってない。どうするかな。


追記:

じゃなくて最初から自分でやったのかも。覚えてない。ようは空きが減ってる。


バックアップ見たらやっぱりそうだった。

パーティション切ってるわけじゃないから勝手に増えるんかなあと思ってしまったのだった。

トラックバック - http://rubyist.g.hatena.ne.jp/hatecha/20090526

05/24(日) 2009

app-engine-patchそのまま

| app-engine-patchそのまま - たばさの を含むブックマーク はてなブックマーク - app-engine-patchそのまま - たばさの

参照

 app-engine-patchを使ってみる - 西尾泰和のはてなダイアリー


sampleそのままやってみた。application idだけ変えて。

動いた、admin,password設定。

でも何やってるのかまだわかってない。

zip

| zip - たばさの を含むブックマーク はてなブックマーク - zip - たばさの

sys.pathに含まれるパスにZIPファイルがあるとそれをディレクトリとして扱う。

zipimport自体はあらためてimportする必要はない。

app engineの制限により含められるのは.pyだけ、.pycはサポートしない。

1000ファイル制限に対処するのに使える。

1MB制限に対処するための分割とimportの仕方。


参照

Error 404 (Not Found)!!1

no title

トラックバック - http://rubyist.g.hatena.ne.jp/hatecha/20090524

05/22(金) 2009

google accountなど、memo

| google accountなど、memo - たばさの を含むブックマーク はてなブックマーク - google accountなど、memo - たばさの

Error 404 (Not Found)!!1

はてなブログ

>GqlQuery instance: methods

bind() クエリー再利用。速い。クエリー文字列をパースしなおさないから

キーの名前やIDってのはクエリではプロパティ値みたくは使えないんだが、自分で名前をつける場合なんかは、それを別途プロパティに保存しとけば似たようなことは出来るぜ!

Error 404 (Not Found)!!1

class StringProperty(verbose_name=None, multiline=False, ...) 500バイト

class TextProperty() 長い文字列。


> Datastore Python API Overview

制限

entityサイズlimit 1MB

put(),delete() 500entities

entityのvalue 1000個

get(),offset 1000

Error 404 (Not Found)!!1

>Google Accounts Python API Overview

google accountを使って堅固で簡単に認証を使ったサービスが作れる。

もちろんこれを使わないで独自にやるのも自由。

ユーザーは(google account、gmailアドレスとパスワードで)アプリのサインインを経なければサインインした事にならない。たとえすでに別のアプリでgoogle accountを使ってサインインしていても。

google account APIの返すUserオブジェクトが使える。Userの値は不変値としては使えない。

そのユーザーが仮にemailアドレスを変えたらもう参照できないから。

このUserオブジェクトはaccount有効中であればemailアドレスを変えても同一性が保障されるユニークIDを持つ。アプリのdatastoreでemailアドレスとuseID両方使いたければ、UserオブジェクトとそのオブジェクトにあるuserIDを別々のプロパティに保存しておくといい。


Error 404 (Not Found)!!1

keyは文字列にしてアプリの外に渡せる。文字列をkeyオブジェクトに戻すにはKeyコンストラクタの引数に渡す。

key_name = self.request.get('key')

obj = db.get(db.Key(key_name))




emailアドレスを変えても??

google accountとgmailは別のサービスなんだな。勘違いしていた。

gmailの場合は気づかないうちに使っている。なのでユーザー名(=gmail)は変更できない。

gmailでないアドレスでgoogle accountを作った場合は他のメールアドレスにいつでも変更できる。ということか。

アカウントのメールアドレスを変更する - パソコン - Google アカウント ヘルプ

gae/java, eclipse 導入

|  gae/java, eclipse 導入 - たばさの を含むブックマーク はてなブックマーク -  gae/java, eclipse 導入 - たばさの

no title など参照


yes, we can!」まで。

全角!で文字化けと、proxomitronとの兼ね合い以外はまあまあ順調に。

プラグイン・インストール時間かかる。

java使ってないので疲れた。eclipseもインストールから。


書いてあるとおり、ひとつのIDでpython,javaversion違いでできた。versionは10までというのはほんとかな。ドキュメントには見かけなかった気がする。

さておき、では言語に関係なくあわせてアプリIDは10個xデータストア1Gということだな。静的ファイルの領域も入ってるんかな?

トラックバック - http://rubyist.g.hatena.ne.jp/hatecha/20090522

05/19(火) 2009

webapp リクエストとアプリ キャッシュ, memo

| webapp リクエストとアプリ キャッシュ, memo - たばさの を含むブックマーク はてなブックマーク - webapp リクエストとアプリ キャッシュ, memo - たばさの

Error 404 (Not Found)!!1

以下で説明するように、すべてのアプリケーションで main() を使用することをお勧めします。

ハンドラ スクリプトが main() という名前の関数を定義すると、スクリプトとそのグローバル環境がインポートされたモジュールと同様にキャッシュされます。

ハンドラ スクリプトをキャッシュするには、App Engine は引数を使用せずに main() を呼び出すことができなければなりません。

注: リクエスト間で、ユーザーの個人情報を「漏らさない」ように注意してください。

トラックバック - http://rubyist.g.hatena.ne.jp/hatecha/20090519

05/18(月) 2009

free Quotas

| free Quotas - たばさの を含むブックマーク はてなブックマーク - free Quotas - たばさの

制限を越えるとアプリはover quotasという表示になる。24時間ごとにリセットされる。日本時間では16時?


有料は従量制。

一日の予算を設定する。設定した上限以上は課金されることはない。

無料分しか使わなければ無料。使った分だけ課金。

予算変更はいつでもできる。

増やす場合はgoogle checkoutの確認後15から30分で有効になる。

減らす場合はgoogle checkoutも必要なく、15分以内に有効になる。

招待されたほかの開発者は一日の予算と割当てを変更できるが、管理者の設定したgoogle checkoutの週間上限まで。予算に税は含まれない。


Error 404 (Not Found)!!1

no title

mixiアプリ メモ

mixiアプリ メモ - たばさの を含むブックマーク はてなブックマーク - mixiアプリ メモ - たばさの

んークワガタくらいにしておこうよ

短縮URL 作ってみた

| 短縮URL 作ってみた - たばさの を含むブックマーク はてなブックマーク - 短縮URL 作ってみた - たばさの

まあ短くはないですが。

http://tabasano-app.appspot.com/u

http://tabasano-app.appspot.com/go/test <= 好きな英数文字列で登録



shorturl.htm

<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>short url - 好きな名前で</title>
</head>
<body>
<div>{{name}}</div>
<div>=> <a href='{{url}}'>{{exp}}</a></div>
<br>
リダイレクトを追加します
  <form action="/u/add">
    http://tabasano-app.appspot.com/go/<input name="name" size=30>
<br> => url:
<input name="url" size=90>
<button>登録</button>
  </form>
</body>
</html>

shorturl.py

# -*- coding : utf-8 -*-

import os
import wsgiref.handlers

from google.appengine.ext import webapp
from google.appengine.ext import db
from google.appengine.ext.webapp import template

class ShortUrl(db.Expando):
    name = db.StringProperty()
    url = db.StringProperty()

class MainPage(webapp.RequestHandler):
    def get(self):
        template_values = {
            'user': "u"
        }
        tmpl = os.path.join(os.path.dirname(__file__), 'shorturl.htm')
        self.response.out.write(template.render(tmpl, template_values))

class SubPage(webapp.RequestHandler):
    def get(self,match):
        q = db.GqlQuery("SELECT * FROM ShortUrl"
                                   " WHERE name = :name", name=match)
        result=q.get()
        tmpl = os.path.join(os.path.dirname(__file__), 'shorturl.htm')
        if result is None:
            url="(not found)"
        else:
            url=result.url
        template_values = {
            'name': "http://tabasano-app.appspot.com/go/"+match,
            'url': url,
            'exp': url
        }
        self.response.out.write(template.render(tmpl, template_values))

class Go(webapp.RequestHandler):
    def get(self,match):
        q = db.GqlQuery("SELECT * FROM ShortUrl"
                                   " WHERE name = :name", name=match)
        result=q.get()
        tmpl = os.path.join(os.path.dirname(__file__), 'shorturl.htm')
        if result is None:
            self.response.out.write("bad url")
            return
        self.redirect(result.url)

class AddUrl(webapp.RequestHandler):
    def get(self):
        name = self.request.get("name")
        url = self.request.get("url")
        if name=="" or url=="" or len(url)<12 or url[:4]!="http":
            self.response.out.write("bad data")
            return
        q = db.GqlQuery("SELECT * FROM ShortUrl"
                                   " WHERE name = :name", name=name)
        result=q.get()
        if result is not None:
            tmpl = os.path.join(os.path.dirname(__file__), 'shorturl.htm')
            template_values = {
                'name': name+" ( is already exist! )",
                'url': result.url,
                'exp': result.url
            }
            self.response.out.write(template.render(tmpl, template_values))
            return
        newurl = ShortUrl(name=name,
                              url=url)
        newurl.put()
        self.redirect("/u/"+name)


def main():
    application = webapp.WSGIApplication([('/u', MainPage),
                                          ('/u/add', AddUrl),
                                          ('/u/(\w+)', SubPage),
                                          ('/go/(\w+)', Go)
                                         ], debug=False)
    wsgiref.handlers.CGIHandler().run(application)

if __name__ == "__main__":
    main()

app.yaml

application: tabasano-app
version: 1
runtime: python
api_version: 1

handlers:
- url: /u
  script: shorturl.py
- url: /u.*
  script: shorturl.py
- url: /go/.*
  script: shorturl.py

f:id:hatecha:20090518170339j:image


(ここではdb.Expandoを使ってみようとして継承したけれど機能は使ってないのでdb.Modelでもおなじ)

class めも

| class めも - たばさの を含むブックマーク はてなブックマーク - class めも - たばさの

python

>>> class Parent:
...   pass
...
>>> class Child(Parent):
...   def pri(self,dat):
...     print "dat="+dat
...
>>> c=Child()
>>> c.pri(12)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 3, in pri
TypeError: cannot concatenate 'str' and 'int' objects
>>> c.pri("12")
dat=12
>>>

ruby

irb(main):001:0> class Parent
irb(main):002:1> end
=> nil
irb(main):013:0> class Child<Parent
irb(main):014:1>   def pri dat
irb(main):015:2>       print"dat=#{dat}"
irb(main):016:2>   end
irb(main):017:1> end
=> nil
irb(main):018:0> c=Child.new
=> #<Child:0x2c744b0>
irb(main):020:0> c.pri 12
dat=12=> nil
トラックバック - http://rubyist.g.hatena.ne.jp/hatecha/20090518

05/17(日) 2009

urlfetchとmemcacheを使ってみるテスト

| urlfetchとmemcacheを使ってみるテスト - たばさの を含むブックマーク はてなブックマーク - urlfetchとmemcacheを使ってみるテスト - たばさの

カウンタととりあえずhtmlまるごととヘッダーを表示。

不特定多数がアクセスしてもcacheのデータが使われる。と思っていいんでしょうか。

f:id:hatecha:20090517045440j:image

f:id:hatecha:20090517045441j:image

memcachetes.py

#!python
# -*- coding: utf-8 -*-
# cf.
# d.hatena.ne.jp/technohippy/20080717
# code.google.com/appengine/docs/memcache/

import os
import wsgiref.handlers

from google.appengine.api import users
from google.appengine.ext import db,webapp
from google.appengine.ext.webapp import template
from google.appengine.api import memcache,urlfetch 
import urllib

def existcache(key):
  data=memcache.get(key)
  if data == None:
    return False
  else:
    return True

def get_data(key):
  data = memcache.get(key)
  if data is not None:
    return data
  else:
    data = 0
    memcache.add(key, data, 60)
    return data

def guess_charset(data): 
   """www.freia.jp/taka/blog/571""" 
   f = lambda d, enc: d.decode(enc) and enc  
  
   try: return f(data, 'utf-8')  
   except: pass  
   try: return f(data, 'shift-jis')  
   except: pass  
   try: return f(data, 'euc-jp')  
   except: pass  
   try: return f(data, 'iso2022-jp')  
   except: pass  
   return None  
  
def conv(data,e):  
   charset = guess_charset(data)  
   u = data.decode(charset)  
   return u.encode(e)


class SubPage(webapp.RequestHandler):
  def get(self,match):
    url=urllib.unquote(match)
    lasturl =memcache.get("url")
    reset=False
    if reset or (existcache("url") ==False) or (url !=lasturl) or (existcache("content") ==False):
      result = urlfetch.fetch(url)
      enc=guess_charset(result.content)
      tmp=unicode(result.content,enc).encode("utf_8")
      if result.status_code == 200:
        memcache.set(key="url", value=url, time=900)
        memcache.set(key="content", value=tmp+"(cache)", time=900)
        memcache.set("counter",0)
    content=memcache.get("content")
    memcache.incr("counter")
    c=memcache.get("counter")
    template_values = {
      "counter":c,
      "url":content+url
    }
    tmpl = os.path.join(os.path.dirname(__file__), 'mem.htm')
    self.response.out.write(template.render(tmpl, template_values))

class MainPage(webapp.RequestHandler):
  def get(self):
    url="http://d.hatena.ne.jp/hatecha/"
    self.redirect('/my/memcache/'+url)

def main():
    application = webapp.WSGIApplication([('/my/memcache', MainPage),
                                         ('/my/memcache/(.+)', SubPage)
                                         ], debug=True)
    wsgiref.handlers.CGIHandler().run(application)

if __name__ == "__main__":
    main()

mem.htm

<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
</head>
<body>
  <dev>{{counter}}</dev>
  <dev>{{content}}</dev>
  <dev>{{fetch_header}}</dev>
</body>
</html>

app.yaml

application: app-id
version: 1
runtime: python
api_version: 1

handlers:
- url: /my/memcache
  script: memcachetes.py
- url: /my/memcache/(.*)
  script: memcachetes.py

いろいろ手抜き

MainPage,SubPageはたぶんredirectするんだと思うけどとりあえず。(した)

http://tabasano0001.appspot.com/my/memcache/http://{ なにか }

でアクセス。


remote cache hitというのは、urlfetchのcacheを使ってるってことか.

PolyModel,memcacheなど memo

| PolyModel,memcacheなど memo - たばさの を含むブックマーク はてなブックマーク - PolyModel,memcacheなど memo - たばさの

Expando:
  Modelのサブクラス
  動的プロパティがもてる
  プロパティ削除は
   del myobj.myproperty
PolyModel: google.appengine.ext.db.polymodel module.
  Modelのサブクラス
  methodをいくつかoverrideしてある
  superclass
  queryのresultはサブクラスのインスタンスを含められる
  Expandoと違い動的propertyは持たない。
  Expandoに対するPolyModelはない。
  ポリモーフィズム。
  PolyModel.class_key()
  自身とすべての親クラス名をtupleとして返す
 PolyModel.class_name()
  クラス名を返す。overrideしていいがentityはオリジナルのクラス名を
  使い続けなければならない
  
Gql
  以下の二つは同じ。
  GqlQuery("SELECT * FROM Song WHERE composer = :composer", composer="Lennon, John")
  Song.gql("WHERE composer = 'Lennon, John'")
memcache
  cacheのlimitは1MB
  Keyの長さは250バイトまで (規定はなし?)

memcacheのとこになぜかMail serviceって書いてあるけど間違いかな。


参考

Error 404 (Not Found)!!1

Error 404 (Not Found)!!1

mixi engineer blog

トラックバック - http://rubyist.g.hatena.ne.jp/hatecha/20090517

05/16(土) 2009

一番簡単なgae

| 一番簡単なgae - たばさの を含むブックマーク はてなブックマーク - 一番簡単なgae - たばさの

いちおう

app.yaml

application: tabasano-app
version: 1
runtime: python
api_version: 1

handlers:

- url: /.*
  static_files: index.html
  upload: index.html

index.html

<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>tabasano!</title>
</head>
<body>
 hello!
</body>
</html>

おなじのをtabasano-でやったら動かない気がする。アドレスのせい?何をおいても動かない。アップロードでエラーはない。うーん。10個のアドレスのうち1個を無駄にしてしまったか。



短くて覚えやすいのないかね。

memcache, utf

| memcache, utf - たばさの を含むブックマーク はてなブックマーク - memcache, utf - たばさの

memcache カウンタ練習。

(Error 404 (Not Found)!!1)

# -*- coding: utf-8 -*-

先頭にこれを入れ忘れる。ローカルでは動くので気付きにくい。エディタのスクロールミスで3行目あたりに入れてしまったり。そんなエディタ使うなと言われそうか。

あとはいまのところ特になし。

膨大なアクセスのあるものを作らないといまいち有り難味はないか。


めも:期限

現在時刻からの相対秒数 (最大 1 か月) または絶対 Unix エポックタイムとなる任意の有効期間。デフォルトではアイテムに期限はありませんが、メモリ不足により強制排除される場合があります。

http://code.google.com/intl/ja/appengine/docs/memcache/clientclass.html

kaorumorikaorumori2009/05/16 13:02僕も「nya-」っていう名前で登録したやつが動かなかったです。
もったいない。

hatechahatecha2009/05/16 13:10ああ、やっぱアドレスですかねぇ

トラックバック - http://rubyist.g.hatena.ne.jp/hatecha/20090516

05/15(金) 2009

GqlQuery, key

| GqlQuery, key - たばさの を含むブックマーク はてなブックマーク - GqlQuery, key - たばさの

つづき。

f:id:hatecha:20090515224830j:image

data viewerからkeyをコピーして

where userfile=agx0YWJhc2Fuby1ncWxyDwsSC...

などとやってもだめだった。

key()というのがそれっぽいので試行錯誤。

>>> q = db.GqlQuery("SELECT * FROM UserFile")
>>> u=q.get()
>>> u
<up.UserFile object at 0x0110EAB0>
>>> u.name
u'csv-upload-in-gae.jpg'
>>> u.key()
datastore_types.Key.from_path('UserFile', 1017L, _app=u'tabasano-gql')
>>> q = db.GqlQuery("SELECT * FROM FileBin where userfile=:1",u.key())
>>> f=q.get()
>>> f
<up.FileBin object at 0x0111A6F0>
>>> f.userfile.name
u'csv-upload-in-gae.jpg'
>>> f.bin[:100]
'\xff\xd8\xff\xe0\x00\x10JFIF\x00\x01\x01\x01\x00`\x00`\x00\x00\xff\xdb\x00C\x00
\x08\x06\x06\x07\x06\x05\x08\x07\x07\x07\t\t\x08\n\x0c\x14\r\x0c\x0b\x0b\x0c\x19
\x12\x13\x0f\x14\x1d\x1a\x1f\x1e\x1d\x1a\x1c\x1c $.\' ",#\x1c\x1c(7),01444\x1f\'
9=82<.342\xff\xdb\x00C\x01\t\t\t\x0c\x0b\x0c'
>>>

上の画像で、numがmissingになっているのはclass UserFileに項目numを追加する前のデータだから。テストなのでいろいろ追加してみたりするんだけどそういえば変更前のデータもちゃんとアクセスできるな。sqlってできたかなこういうの。

トラックバック - http://rubyist.g.hatena.ne.jp/hatecha/20090515

05/14(木) 2009

blob, Binary Large OBject 分割、結合

| blob, Binary Large OBject 分割、結合 - たばさの を含むブックマーク はてなブックマーク - blob, Binary Large OBject 分割、結合 - たばさの

やろうとしたものがこちらにあった。

no title

filebin_setのとこが分からなかったけどあとで探そう。


削除部分が抜けているような気がするのでやってみた。


   def delete(self):
       results = self.filebin_set.fetch(10)
       for result in results:
           result.delete()
       super(UserFile, self).delete()

手元のとは細かく違うので試していないんですが。




Queryで選択したくて

        q = db.GqlQuery("SELECT * FROM FileBin where userfile=...")
        results = q.fetch(count)

などとやってみたんだけど、userfile=...のところに何を入れたらいいか分からない。

UserFile(db.Model)のインスタンス。


indexが更新されなくて困った。エラーメッセージにこういうindexが必要、と出たのでindex.yamlにコピペして

appcfg.py update_indexes [app-id]

で更新。


立体視lisp式

立体視lisp式 - たばさの を含むブックマーク はてなブックマーク - 立体視lisp式 - たばさの

ていうのを考えた。ステレオグラム

トラックバック - http://rubyist.g.hatena.ne.jp/hatecha/20090514

05/13(水) 2009

yaml

| yaml - たばさの を含むブックマーク はてなブックマーク - yaml - たばさの


application: app-id
version: 1
runtime: python
api_version: 1

handlers:
- url: /(.*)
  static_files: /\1
  upload: /(.*)

handlerは上から順にみて最初に正規表現がマッチしたものが使われる。

二種類あって、scriptとstatic file

うえのようにしてindex.htmlでも何でもおいて、appcfg.py update app-idすればよきに計らってアップしてくれる。static_files:のときはupload:を書かないとエラーが出た。

削除のタイミングはどうだろう。テストしたら、ローカルのファイルを削除して再度appcfg.py update app-idするとアクセスできなくなる。でも削除されてるかはわからないよね。気にしなくていいかな。http://appengine.google.com/の設定画面でバージョンの切り替えが出来るしバージョン別にチェックするためのアドレスもあるということは保存してあるということで、どこまで保存してあるんだろうか。

アップロードの制限は、10MBでエラーになった。データストアの制限は1MB。10MB処理したければ分割すればいいというかするしかない。

ということで

http://d.hatena.ne.jp/ikasamaH/20080612/p1

ありました。ソースを見て解読しよう。パスを変えてみてテスト。動いた。すごい。

コメントのほうによさそうなのがあるが一気にサイズが10倍になるようなのでびびって断念。まあ分割については,バイナリはBlobというProperty classらしいのでBlobでソースを検索すればいいでしょう。


適当にサイズの大きいファイルを開いてみる。例のconsole

>>> mm = db.Blob(open("binary_file","rb").read())
>>> n=len(mm)
>>> n
76096574
>>> mid=n/2
>>> b1=mm[0:mid]
>>> b2=mm[mid:n]
>>> bb=b1+b2
>>> bb==mm
True
>>>
トラックバック - http://rubyist.g.hatena.ne.jp/hatecha/20090513

05/12(火) 2009

transaction

| transaction - たばさの を含むブックマーク はてなブックマーク - transaction - たばさの

transaction:いちどにデータストアなどを行う。すべて成功かすべて失敗するか。

失敗したらロールバックする。複数のユーザのリクエストがあるときなどに使うといい。

失敗したらデフォルトでは3回までリトライする。というわけで何度呼ばれるか分からないtransactionのなかに副作用のあるコードを書いてはいけない。

データの準備は前もってする。

def double(li):
    db.put(li)

q = db.GqlQuery("SELECT * FROM Message")
li = q.fetch(100)
for i in li:
  print i.key()
for i in li:
  i.content += " +update2"
for i in li:
  print i,i.key(),i.id,i.content,i.date

db.run_in_transaction(double,li )
BadRequestError: Cannot operate on different entity groups in a transaction: (kind=u'Message', id=5L) and (kind=u'Message', id=10L).
>>>

こんなエラーが出る。エンティティ・グループが同一でないといけないらしい。

id=5Lというのは自動的に振り当てられた一意のidで、自分で指定するには作成時にkey_name=...を使う。

エンティティ作成時にparent entityを設定できる。おなじparentをもつエンティティがおなじエンティティ・グループに属し、一回のtransactionで処理できるようになる。parentは変更できない。parentが削除されても子は削除されず、Keypathでアクセスできる。tree構造らしいが、pathの説明はどこ?

parentは実際には存在しなくてもいい、かな?

parent指定がなければroot entityになる。エンティティ・グループはqueryの速度にはあまり影響しない。transactionの必要がない場合の関係付けはReferencePropertyとKeyで。

http://appengine.google.com

data viewerではparent項目はないのでチェックできないが、transactionで操作してみると一度に削除などができるのが分かる。


以下、またappengine_console.pyで。

>>> sys.path.append("tabasano-gql")
>>> import mymain
# parentが同一(parentmes)のentityを作ってみる。
>>> pt=m.Message(id="g-id 2 no",content="g-content tes 2 no")
>>> ss=[m.Message(parent=pt,id="g-id child of pt",content="virtual parent; %d"%n) for n in range(10)]
Traceback (most recent call last):
  File "<console>", line 1, in <module>
  File "C:\Program Files\Google\google_appengine\google\appengine\ext\db\__init__.py", line 575, in __init__
BadValueError: Message instance must have a complete key before it can be used as a parent.
>>> pt=m.Message(key_name="parent-tes",id="g-id 2 no",content="g-content tes 2 no")
>>> ss=[m.Message(parent=pt,id="g-id child of pt",content="virtual parent; %d"%n) for n in range(10)]
>>> for i in ss:i.put()
...
datastore_types.Key.from_path('Message', u'parent-tes', 'Message', 1L, _app=u'tabasano-gql')
datastore_types.Key.from_path('Message', u'parent-tes', 'Message', 1001L, _app=u'tabasano-gql')
datastore_types.Key.from_path('Message', u'parent-tes', 'Message', 2L, _app=u'tabasano-gql')
datastore_types.Key.from_path('Message', u'parent-tes', 'Message', 1002L, _app=u'tabasano-gql')
datastore_types.Key.from_path('Message', u'parent-tes', 'Message', 3L, _app=u'tabasano-gql')
datastore_types.Key.from_path('Message', u'parent-tes', 'Message', 4L, _app=u'tabasano-gql')
datastore_types.Key.from_path('Message', u'parent-tes', 'Message', 5L, _app=u'tabasano-gql')
datastore_types.Key.from_path('Message', u'parent-tes', 'Message', 1003L, _app=u'tabasano-gql')
datastore_types.Key.from_path('Message', u'parent-tes', 'Message', 1004L, _app=u'tabasano-gql')
datastore_types.Key.from_path('Message', u'parent-tes', 'Message', 6L, _app=u'tabasano-gql')
>>>

key_nameがないとparentにできないようだ。あれば実際にparentをput()しなくても子が追加できた。

ということでいいのかな。


自動で割り当てられるidは連続とは限らないのでdata viewerではqueryで

SELECT * FROM Message order by date desc

などと適当なキーで並べ替えるといいでしょう。

f:id:hatecha:20090512104549j:image

追記:

適当なと書いたけれど。gql解説によれば order by id, content,などと組み合わせられるとあるのでやってみたがどうもindex.yamlで設定してある組合せしか使えないようだ。当然か。

- kind: Message
  properties:
  - name: id
  - name: content
  - name: date
    direction: desc

がある場合

order by id,content,date

はエラーで

order by id,content,date desc

は通る。


参考

Error 404 (Not Found)!!1

Error 404 (Not Found)!!1

python日記になってしまいそうな。

python日記になってしまいそうな。 - たばさの を含むブックマーク はてなブックマーク - python日記になってしまいそうな。 - たばさの

jruby使えるかなーと思ったんだけど道のりは遠いな

トラックバック - http://rubyist.g.hatena.ne.jp/hatecha/20090512

05/11(月) 2009

proxomitronだった

| proxomitronだった - たばさの を含むブックマーク はてなブックマーク - proxomitronだった - たばさの

http://appengine.google.com/api/updatecheck

ここでチェックしてるんだなー。

ソースを見てproxomitronがいれた前後のタグに気がついた



エラーメッセージから

google\appengine\tools\appcfg.py, dev_appserver_main.pyなどを見た。


文字列検索

..\google\appengine\tools>findstr ForUpdate *.py
appcfg.py:  def CheckForUpdates(self):
appcfg.py:  def AllowedToCheckForUpdates(self, input_fn=raw_input):
appcfg.py:    updatecheck.CheckForUpdates()
dev_appserver_main.py:    if update_check.AllowedToCheckForUpdates():
dev_appserver_main.py:         update_check.CheckForUpdates()

..\google\appengine\tools>

dev_appserver_main.py

  if option_dict[ARG_ADMIN_CONSOLE_SERVER] != '':
    server = MakeRpcServer(option_dict)
    update_check = appcfg.UpdateCheck(server, config)
    update_check.CheckSupportedVersion()
    if update_check.AllowedToCheckForUpdates():
         update_check.CheckForUpdates()

appcfg.py

  def CheckForUpdates(self):
    """Queries the server for updates and nags the user if appropriate.

    Queries the server for the latest SDK version at the same time reporting
    the local SDK version.  The server will respond with a yaml document
    containing the fields:
      "release": The name of the release (e.g. 1.2).
      "timestamp": The time the release was created (YYYY-MM-DD HH:MM AM/PM TZ).
      "api_versions": A list of api_version strings (e.g. ['1', 'beta']).

    We will nag the user with increasing severity if:
    - There is a new release.
    - There is a new release with a new api_version.
    - There is a new release that does not support the api_version named in
      self.config.
    """
...
    try:
      response = self.server.Send("/api/updatecheck",
                                  timeout=UPDATE_CHECK_TIMEOUT,
                                  release=version["release"],
                                  timestamp=version["timestamp"],
                                  api_versions=version["api_versions"])
...
トラックバック - http://rubyist.g.hatena.ne.jp/hatecha/20090511

05/09(土) 2009

google app engine SDK 1.2.2

| google app engine SDK 1.2.2 - たばさの を含むブックマーク はてなブックマーク - google app engine SDK 1.2.2 - たばさの

1.1.0、1.2.1ともエラー。

SDKを1.2.2にしたら動いた。念のためパスを変えてインストールしたのに古いほうのを一部消された?

ログイン - Google アカウント

しかしまあ、これみると圧倒的にMacが多いんでしょうか

f:id:hatecha:20090509105606j:image

古いの見るとそうでもない。アップデートしてないだけ?


追記:

errorで最後の行にrelease: "1.2.2"と出ていた。まさかエラーで周知じゃないよな、実行してるのは手元だし。ということで「release: "1.2.2"」でPCの中を検索したりSDKアンインストールしてみたりしてしまった。


「Checking for updates to the SDK.」

そうかーサーバを起動するときチェックするメッセージでてるんだな。読まないし。

remote_api使ってみる

| remote_api使ってみる - たばさの を含むブックマーク はてなブックマーク - remote_api使ってみる - たばさの

appengine_console.py

( http://code.google.com/intl/en/appengine/articles/remote_api.html )

パスを書き換えたりで、プロンプトまではどうにか。

(以下はすべてappengine_console.pyでのコンソール画面。)


putするまで

...
>>> import tes
>>> message = tes.Message(content="upload from local")
>>> message.put()
Traceback (most recent call last):
  File "<console>", line 1, in <module>
  File "...\google\appengine\ext\db\__init__.py", line 669, in put
...
  File "..Python25\lib\urllib2.py", line 353, in _call_chain
    result = func(*args)
  File "..Python25\lib\urllib2.py", line 499, in http_error_default
    raise HTTPError(req.get_full_url(), code, msg, hdrs, fp)
HTTPError: HTTP Error 404: Not Found
>>>

わからんなー



"Usage: %s app_id [host]" % (sys.argv[0],)

第二引数はhostか。 {app_id}.appspot.comにしたらHTTP Errorはなくなった。でもまだ

BadRequestError: app tabasano-gql cannot access app tes's data

アクセスできない?、、ひょっとしてフォルダ名か。*1フォルダ名をapp_id(tabasano-gql)と同じに変えたら

localからbigtableにdatastoreできたー。


って使い方あってる?



追記:

downloadもやってみる。

>>> sys.path.append("tabasano-gql")
>>> import mymain
>>> entry = mymain.Message.all()
>>> entry
<google.appengine.ext.db.Query object at 0x00D9A6F0>
>>> for i in entry:
...   print i
...
Username: ....
Password:
<m.MessageN object at 0x0112A030>
...
<m.MessageN object at 0x0112A030>
<m.MessageN object at 0x0112BBD0>
>>> for i in entry:
...   print i.content
...
ba
ないようです。
naiyo.
naiyo.
てすとだ。
てすとだよ。
...

データが呼べた。


mymain.pyには

class Message(db.Model):
    id = db.StringProperty()
    content = db.StringProperty()
    date = db.DateTimeProperty(auto_now_add=True)

というentity.

おかしいな。utf-8だから文字化けすると思ったんだけど。

ログインデータはc:\Documents and Settings\{user}\.appcfg_cookiesに保存されるようだ。(appcfg.pyの場合。このappengine_console.pyでは毎回入力する。)



appcfg.py upload_data

というオプションが追加されている。検索してもとくにみつからない。

(http://code.google.com/intl/ja/appengine/docs/python/tools/uploadingdata.html)



download,うえのだとループの回数だけアクセスする。

entities = mymain.Message.all().fetch(100)
for entity in entities:
  #do something

推奨されているこちらだと最初に一回だけ。送信、受信は1MB制限がある。



deleteする

>>> a = mymain.Message.all().fetch(100)
Username:...
Password:
>>> for i in range(100):print i,a[i].id,a[i].content
...
0 ta ba
1 sa てすとだよ。
2 sa ないよ。
3 sa ないよ
4 idtes ローカルから。
5 sa あいう
6 sa かき
7 sa かきくけ
8 namae ないようです。
9Traceback (most recent call last):
  File "<console>", line 1, in <module>
IndexError: list index out of range
>>> x=[]
>>> for i in a:
...   if i.id=="sa": x.append(i)  # idがsaのもの
...
>>> x
[<m.MessageN object at 0x0112ECB0>, <m.MessageN object at 0x0112EC50>, <m.MessageN object at 0x0112EB30>]
>>> db.delete(x) # 一度に消す
>>> for i in range(100):print i,a[i].id,a[i].content
...
0 ta ba
1 sa てすとだよ。
2 sa ないよ。
3 sa ないよ
4 idtes ローカルから。
5 sa あいう
6 sa かき
7 sa かきくけ
8 namae ないようです。
9Traceback (most recent call last):
  File "<console>", line 1, in <module>
IndexError: list index out of range
# getしなおす。
>>> a = mymain.Message.all().fetch(100)
>>> for i in range(100):print i,a[i].id,a[i].content
...
0 ta ba
1 idtes ローカルから。
2 namae ないようです。
3Traceback (most recent call last):
  File "<console>", line 1, in <module>
IndexError: list index out of range
>>>

参考

GoogleAppEngineでremote_apiを使う s_thx>tmatsuo - When it’s ready.



追記(5/11)

csvデータをアップロード

upload_dataオプションを使ってみる。例にある、

appcfg.py upload_data --config_file=album_loader.py --filename=album_data.csv --kind=Album <app-directory>

これを書きかえて,またパスなど試行錯誤しつつ

 ..\gae> appcfg.py upload_data --config_file=tabasano-gql\message_loader.py --filename=tabasano-gql\mytest.csv --kind=Message tabasano-gql
Uploading data records.
[INFO    ] Logging to bulkloader-log-20090511.084344
[INFO    ] Opening database: bulkloader-progress-20090511.084344.sql3
[INFO    ] Connecting to /remote_api
[INFO    ] [Thread-11] ProgressTrackerThread: started
[INFO    ] [Thread-12] DataSourceThread: started
[INFO    ] Starting import; maximum 10 entities per post
[INFO    ] [Thread-1] BulkLoaderThread: started
[INFO    ] [Thread-2] BulkLoaderThread: started
[INFO    ] [Thread-3] BulkLoaderThread: started
[INFO    ] [Thread-4] BulkLoaderThread: started
[INFO    ] [Thread-5] BulkLoaderThread: started
[INFO    ] [Thread-6] BulkLoaderThread: started
[INFO    ] [Thread-7] BulkLoaderThread: started
[INFO    ] [Thread-8] BulkLoaderThread: started
[INFO    ] [Thread-9] BulkLoaderThread: started
[INFO    ] [Thread-10] BulkLoaderThread: started
[INFO    ] [Thread-12] DataSourceThread: exiting
[INFO    ] [1-3] Batch successfully sent.
[INFO    ] [Thread-4] BulkLoaderThread: exiting
[INFO    ] [Thread-5] BulkLoaderThread: exiting
[INFO    ] [Thread-6] BulkLoaderThread: exiting
[INFO    ] [Thread-7] BulkLoaderThread: exiting
[INFO    ] [Thread-8] BulkLoaderThread: exiting
[INFO    ] [Thread-9] BulkLoaderThread: exiting
[INFO    ] [Thread-10] BulkLoaderThread: exiting
[INFO    ] [Thread-1] BulkLoaderThread: exiting
[INFO    ] [Thread-2] BulkLoaderThread: exiting
[INFO    ] [Thread-3] BulkLoaderThread: exiting
[INFO    ] [Thread-11] ProgressTrackerThread: exiting
[INFO    ] 3 entites total, 0 previously transferred
[INFO    ] 3 entities (1722 bytes) transferred in 1.4 seconds
[INFO    ] All entities successfully transferred

 ..\gae> 

mytest.csv

csv1,content1,2009-05-05 05:50:05
csv2,content2,2009-05-06 05:51:05
csv3,content3,2009-05-07 05:52:05

message_loader.py

# -*- coding: utf-8 -*-
import datetime
from google.appengine.ext import db
from google.appengine.tools import bulkloader
import sys
sys.path.append("tabasano-gql")
from mymain import *

class MessageLoader(bulkloader.Loader):
  def __init__(self):
    bulkloader.Loader.__init__(self, 'Message',
                               [('id', str),
                                ('content', str),
                                ('date',
                                 lambda x: datetime.datetime.strptime(x,'%Y-%m-%d %H:%M:%S'))
                               ])

loaders = [MessageLoader]

mymain.py

# -*- coding: utf-8 -*-
import os
import wsgiref.handlers

from google.appengine.api import mail, users
from google.appengine.ext import db,webapp
from google.appengine.ext.webapp import template

class Message(db.Model):
    id = db.StringProperty()
    content = db.StringProperty()
    date = db.DateTimeProperty(auto_now_add=True)

(...略...)

logも保存されるようです。「途中で失敗したらcsvを直して再開しましょう」と書いてあるので、そのまま再開するとデータが重複するんでしょう。


例ではdate()を使っているところがこちらはdatetimeなので型を直して通りました。

f:id:hatecha:20090511092006j:image

もとのと同じくmicrosecondも使いたかったけど分からなかった。

*1:フォルダ名とアプリ登録名を違うものにしていた。app.yamlにちゃんと書けば動いたので。

トラックバック - http://rubyist.g.hatena.ne.jp/hatecha/20090509

05/07(木) 2009

dumpしてみる

| dumpしてみる - たばさの を含むブックマーク はてなブックマーク - dumpしてみる - たばさの

ダンプを保存

sqlite3 test.db .dump > sql_backup.txt

できた sql_backup.txt

BEGIN TRANSACTION;
CREATE TABLE moz_bookmarks (id INTEGER PRIMARY KEY,type INTEGER, fk INTEGER DEFAULT NULL, parent INTEGER, position INTEGER, title LONGVARCHAR, keyword_id INTEGER, folder_type TEXT, dateAdded INTEGER, lastModified INTEGER);
INSERT INTO "moz_bookmarks" VALUES(1,2,NULL,0,0,'',NULL,'',1205363189421875,1238067049203125);
INSERT INTO "moz_bookmarks" VALUES(2,2,NULL,1,0,'ブックマークメニュー',NULL,'',1205363189437500,1212794635234375);
...(略)
COMMIT;

ダンプから作成してみる

sqlite3 recovery.db < sql_backup.txt

ロックしてあると使えないな。




>sqlite3 -help
Usage: d:\download\sqlite-3_5_7\sqlite3 [OPTIONS] FILENAME [SQL]
FILENAME is the name of an SQLite database. A new database is created
if the file does not previously exist.
OPTIONS include:
   -init filename       read/process named file
   -echo                print commands before execution
   -[no]header          turn headers on or off
   -bail                stop after hitting an error
   -interactive         force interactive I/O
   -batch               force batch I/O
   -column              set output mode to 'column'
   -csv                 set output mode to 'csv'
   -html                set output mode to HTML
   -line                set output mode to 'line'
   -list                set output mode to 'list'
   -separator 'x'       set output field separator (|)
   -nullvalue 'text'    set text string for NULL values
   -version             show SQLite version

>
トラックバック - http://rubyist.g.hatena.ne.jp/hatecha/20090507

05/06(水) 2009

また携帯認証か

| また携帯認証か - たばさの を含むブックマーク はてなブックマーク - また携帯認証か - たばさの

orkutでopensocial入門たどってたのになぜかgoogle app engineはじめてた。*1

いろいろつまずいたけどなんとか。hello.

http://tabasano0001.appspot.com/


memo:

携帯でSMSというのを使えないからだめだったらしい問題は解決してたらしいということでどうにかアドレス入力へ。

なぜに20byte制限?

どうにかハイテクで潜り抜けて(広げて)登録。proxomitronで。greasemonkeyでもいいかな。

app登録は10個まで。削除は出来ない。


参考

Entry is not found - Labs

Google App Engine詳解:さっそくHello Worldから作ってみた - builder by ZDNet Japan

ログイン - Google アカウント

*1:hostingにはgaeがあるよっていわれた気が

トラックバック - http://rubyist.g.hatena.ne.jp/hatecha/20090506

05/05(火) 2009

はてブ,エクスポートでhtmlからrssに

| はてブ,エクスポートでhtmlからrssに - たばさの を含むブックマーク はてなブックマーク - はてブ,エクスポートでhtmlからrssに - たばさの

調子が悪くてrss版が落とせなかった。atomも。htmlはダウンロードできた。

atomは一度成功と思ったらリンクがブクマ元のほうがなくてはてブのアドレスになってる気が。

まあhtmlのを変換すればいいか、と思いどうにか変換してyahooにインポート!したがどうも失敗。

仕方ないので分割してみた。

#!ruby
# -*- encoding: "UTF-8" -*-
require 'rss'
require 'time'

rss_feeds = []
rss_urls = []
title="" 

if ARGV[1]==nil
  puts "usage:%0 infile outfile [maxItemNumPerFile]\n hateb_backup_html to rss"
  puts opt.to_s
  exit
end

rsslist=[]

ary=[]
n=0
data=(File.readlines(ARGV[0])*"").gsub(/\n/){""}.gsub(/<\/A>/i){"</A>\n"}.gsub(/<DT>/){"\n<DT>"}.split("\n")
data.each{|i|
  i.scan( /<DT><A HREF="(.*)" ADD_DATE="(\d+)".*>(.*)<\/A>/i){|u,d,t|
    #break if $debug && n>5 
    ary<<[u,d,t]
    n+=1
  }
}
$stderr.puts ary.size
n=0

# cf. http://homepage2.nifty.com/takaaki024/tips/programs/ruby/ruby.html
onePercent=ary.size/100
onePercent=1 if onePercent==0
max=ary.size
max=ARGV[2].to_i if ARGV[2]
h=[]
num=0
0.step(ary.size, max){|i| h<<i}

h.each{|start|
  num+=1
  iary=ary[start,max]

  rss = RSS::Maker.make('1.0') do |maker|
    # RSSファイル1つに対して1回だけ設定する項目
    maker.channel.about       = ''
    maker.channel.title       = 'はてぶ'
    maker.channel.description = 'サイトの説明'
    maker.channel.link        = 'http://b.hatena.ne.jp/hatecha/'
    maker.channel.date        = Time.now

    maker.image.title         = ''
    maker.image.url           = ''

    # 更新日の新しい順に並べ替えるオプション
    maker.items.do_sort = true

    iary.each_with_index{|a,n|
      url,date,title=a
      maker.items.new_item do |item|
        item.link            = url
        item.title           = title
        item.description     = ''
        item.dc_subject      = ''
        item.content_encoded = ''
        item.date= Time.at(date.to_i)
      end
      #$stderr.print"." if n%onePercent==0
    }
  end
# 書き出す
  open("#{ARGV[1]}_#{num}.rss","w"){|f|
     f.puts rss.to_s
  }
  print num,","

}

1000フィードずつにしたらインポートできた。数が少ない気がするけどまあいいや。あとで調べようか。

そうこうしてるうちにRSS版が落とせた。んー。


メモ:

unix timeをあーでもないこーでもないと変換したら一時間ずれた。などとやったあとTime.at発見。まああるよね。

nkfutf-8オプションwをずっとuに間違ってた。エラーにはならないから。

・もっと読みやすく書けないものか



あーでもないっていうのは

irb(main):009:0> Time.parse("1970-01-02")
=> Fri Jan 02 00:00:00 +0900 1970
irb(main):010:0> Time.parse("1970-01-01")
ArgumentError: time out of range

localだから?

irb(main):001:0> Time.at 0
=> Thu Jan 01 09:00:00 +0900 1970
トラックバック - http://rubyist.g.hatena.ne.jp/hatecha/20090505

05/04(月) 2009

sqlite3はutf-8.

| sqlite3はutf-8. - たばさの を含むブックマーク はてなブックマーク - sqlite3はutf-8. - たばさの

windowsで文字化けして困る。chcpなど調べるもうまくいかない。

sqlite3、ソースあるから書き換えればいいんじゃね。


いいんじゃね


iinjane ...





というのは無理なので。

現実的に、とりあえずこれで足りそう。というか我慢。

sj.bat

%* | ruby -rkconv -ne'puts $_.tosjis'

sj sqlite3 db.db "select * from table where date like '2009-05-%' "

とか。

トラックバック - http://rubyist.g.hatena.ne.jp/hatecha/20090504
カレンダー
<< 2009/05 >>
1 2
3 4 5 6 7 8 9
10 11 12 13 14 15 16
17 18 19 20 21 22 23
24 25 26 27 28 29 30
31
archive Error : RSSが取得できませんでした。