• 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
 

PokéDiaでは非公開APIは使っていないのですが、 iPhone OS 2.0から iPhone OS 2.1, 2.2, 2.2.1, そして3.0と、OSのバージョンアップにあわせて変動する微妙な挙動の変化への対応などから、相当な歪みが蓄積している状態になってしまっています。 特に任意の場所でテキスト入力を実現する機能の実現に非常に苦労しており、OS 3.0では画面端での日本語入力の変換候補選択がうまく行かない問題等も出てきました。 また、作者の環境では発生しないために修正ができないバグなども多数報告いただいています。

そこで、現状のPokéDiaの開発はデータのエクスポータを用意して一旦停止し、 フルスクラッチで書き直す事を検討しています。

  • 操作をシンプルにするために、縦スクロールを無くしてページを追加できるようにします。
  • データが消えるという問題には、Appleが動作検証をしているCoreDataを利用する事で対応します。
  • 任意位置でのテキスト入力はUITextViewの挙動が不安定なので、表示と編集を分離する方向を検討しています。
  • 機能制限つきの無料版と、有料版の2つを用意します。
    • 既にPokéDiaを買って頂いている方は、エクスポートしたデータを無料版にインポートすると、有料版と同じ機能が使えるようになる予定。
  • 言語リソースはオンラインから取得

などなど。

posted by Png genki on Wed 29 Jul 2009 at 18:04

As I mentioned before, I am making small abstraction FW. For giving the task a vista, I want to make a list of the requirements in advance.

  • Abstract Model (I hope the ActiveORM will be)
  • Basic HTML tag helpers (such as "tag", "url_for")
  • Starting up hook to modify others
  • Way to register helpers
  • Way to read/write configuration of plugin

In particular, abstract model is quite important. There are already several efforts, but they all are probably not succeeding. I think the reason of the failure is what most of them had been concentrating to make abstraction of models for models. It must be designed for agnostic plugins.

Suppose you are an application developer and you are writing some code. Obviously, the FW and ORM have already been chosen. So you have no need to treat various ORMs for making the app. Only agnostic plugins need the abstract model.

What is the requirements of the plugins?

  • read_many with options for specifying :limit and :offset
  • read_one, create, destroy, update
  • read/write access to attributes
  • counting, searching, association and so on.

Is it the DataMapper? Yeah, it is nearly equals to. But it must have more flexibility.

In conclusion, we should not make an abstraction of models but an abstraction of plugin's requirements to FW.

posted by Png genki on Thu 23 Jul 2009 at 21:22

Today, there are many web application frameworks such as RoR, Merb, Ramaze, Sinatra and so on. And then, most of them have original plugin system respectively. It opens curtain of the tragedy entitled "Combinatorial explosion" upon plugin developers.

Just think. FW hackers tend to be opinionated. It is obvious. Because it is the source of energy of his/her great works. But it is a reason of the tragedies as well. Is that a fate of us? It would never be changed?

No, it isn't.

There is a hope we already have. Its name is Rack. Rack is called meta-framework. Most of FWs exploit it today. It saved tons of time of FW hackers to make original HTTP interface for their FW. It must happen for also plugin developers.

I think what they need is not another meta-framework. meta-framework is for FW hackers. Abstract framework is for plugin developers.

I began to make an abstract framework on github. Here is.

http://github.com/genki/agnostic/tree/master

If you have idea, please let me know.

posted by Png genki on Thu 23 Jul 2009 at 18:01

Rub はHaml的なEndless Rubyを気軽にはじめるために作ったGemです。 GitHubをsourceに追加して以下のようにインストールできます。

   1  % sudo gem install genki-rub

ソースコード を見るとわかりますが、非常に短いので現時点では、if文の複数行にまたがる条件文などには対応していません。気が向けばそのうち対応するかもしれません。

Rubを使ってSinatraアプリを作るには以下のようにします。

config.ru

   1  require "rubygems"
   2  require "rub"
   3  rub "app.rb"
   4  run Sinatra::Application

app.rb

   1  require "sinatra"
   2  require "dm-core"
   3  require "haml"
   4  
   5  DataMapper::setup(:default, ENV['DATABASE_URL'] || 'sqlite3://db.sqlite3')
   6  
   7  class Post
   8    include DataMapper::Resource
   9    property :id, Serial
  10    property :content, Text
  11    auto_upgrade!
  12  
  13  get "/" do
  14    @posts = Post.all(:order => [:id.desc])
  15    haml :index
  16  
  17  post "/" do
  18    Post.create(params)
  19    redirect "/"
  20  
  21  __END__
  22  @@ index
  23  %h1 Hello, Sinatra!
  24  %ul
  25    - @posts.each do |post|
  26      %li= post.content
  27  %form{:method => :post}
  28    %textarea{:name => :content}
  29    %input{:type => :submit, :value => "Post"}

面白い点として、 Endless RubyでもVimやこのブログのSyntaxハイライトはちゃんと機能してくれます(Emacs使いのレポート求む)

必要なファイルはこれだけです。あとはおもむろにshotgunしましょう。

   1  % shotgun
   2  == Shotgun starting Rack::Handler::Mongrel on localhost:9393

あとはhttp://localhost:9393にアクセスするだけです。 app.rbを適当に書き換えてリロードすると、変更が反映される事が確認できます。

shotgunは

   1  % sudo gem install shotgun

でインストールできます。

posted by Png genki on Mon 20 Jul 2009 at 05:09 with 2 comments

カンファレンス会場で最も貴重な資源は時間ですが、二番目はきっと電源です。 電力というのは普段は簡単に安く手に入る資源であるにもかかわらず、人が集まる場所では極端に供給が難しくなります。 このギャップはとても大きいので、ビジネスになるのではないかと思います。

非常に大雑把な計算ですが、 普通のノートPCを1日動かす程度電力が供給できれば良いので、 20000円程度で市販されている外部バッテリを年間100日レンタルできたとして、平均耐用年数が1年だったとしても、1日あたり200円です。

カンファレンス会場に据え置いてしまえば輸送コストはそれほどかかりません。カンファレンスはほとんどデイタイムに開催されるので、夜間の安い電力で一括充電できます。 一晩に一人で1000個のバッテリを充電できるとすると、時給2000円でも8時間で16000円/日。バッテリ一個あたり16円。 人件費を考慮しても十分安価にサービスを提供できるのではないでしょうか。

posted by Png genki on Fri 17 Jul 2009 at 05:33

Gemを作るのが面倒になってきたので、githubから直接requireできたら楽になるかもしれないと思い、試してみました。

   1  def git(uri, sha1, options = {})
   2    require "tmpdir"
   3    basename = File.basename(uri)
   4    outdir = File.join(Dir.tmpdir, basename, sha1)
   5    unless File.exist?(outdir)
   6      sh = proc{|command| IO.popen("#{command} 2>&1"){|io| io.read}}
   7      sh["git clone #{uri} #{outdir}"]
   8      sh["cd #{outdir}; git checkout #{sha1}"]
   9    end
  10    $:.unshift File.join(outdir, 'lib')
  11    require options[:require_as] || basename.split(/\.git$/)[0]
  12  end

Dir.tmpdirを使ってOSのテンポラリディレクトリの下にリポジトリをクローンしてきて、指定したリビジョンをcheckoutし、LOAD_PATHに"lib"を加えて、リポジトリ名のファイルをrequireしています。

意外と普通にgemの代わりに使える感じです。

posted by Png genki on Thu 16 Jul 2009 at 17:40

Gist はちょっとしたコードの切れ端を貼付けておくのに便利です。 先日紹介したEndless RubyのコードもGist上でのみ公開されていました。 Gemを作るまでもないコードをGistに貼付けて、そのままrequireして使えると便利そうだと思ったので、試してみました。

   1  module Gist
   2  module_function
   3    def require(id, sha1 = "HEAD")
   4      Kernel.require "open-uri"
   5      gist = "http://gist.github.com"
   6      eval(if sha1 == "HEAD"
   7        open("#{gist}/#{id}.txt").read
   8      else
   9        Kernel.require "tmpdir"
  10        cache = File.join(Dir.tmpdir, "gist-#{id}-#{sha1}")
  11        if File.exist?(cache)
  12          open(cache).read
  13        else
  14          open("#{gist}/raw/#{id}/#{sha1}") do |i|
  15            code = i.read
  16            open(cache, "w"){|o| o.write code}
  17            code
  18          end
  19        end
  20      end)
  21    end
  22  end
  23  
  24  Gist.require("148479", "a59ea9ec3e865bafd1e4413b43b6ccb7a38d76fc")
  25  #=> Hello, world!

Hash値で内容の変更が検出可能なので、md5のチェックサムを信用している人にとっては同程度の安全性で利用できそうです。

posted by Png genki on Thu 16 Jul 2009 at 17:31
14th Tue

Endless Ruby

HAMLを使うようになってから、endの無いrubyが欲しい今日この頃。 あわや自作する直前、先人の仕事を見つけました。

[ANN] Endless Ruby 0.0.2

endless.rb is a pre-processor for ruby which allows you to use python-ish indentation to delimit scopes, instead of having to type 'end' every time.

良いですね。残念ながら、現時点ではrubylexerのrequireでエラーが出るようですが、一定の制約付きでもかまわないので動くようになるとありがたいです。 JRubyのCharles Nutterも割と 肯定的なコメント を寄せていますね。

Oh dear god no!

Seriously though...neat :)

-- Charlie

JRubyのオプションに--endlessがつく?

posted by Png genki on Tue 14 Jul 2009 at 17:41

Merbの開発がなかなか進展しないのでSinatraをちょっと触ってみたところ、 DataMapper、Herokuとの組み合わせが非常に簡単でいい感じでした。

blog.rb

   1  require "rubygems"
   2  require "sinatra"
   3  require "dm-core"
   4  require "haml"
   5  
   6  DataMapper::setup(:default, ENV['DATABASE_URL'] || 'sqlite3:db.sqlite3')
   7  
   8  class Post
   9    include DataMapper::Resource
  10    property :id, Serial
  11    property :content, Text
  12    auto_upgrade!
  13  end
  14  
  15  get "/" do
  16    @posts = Post.all(:order => [:id.desc])
  17    haml :index
  18  end
  19  
  20  post "/" do
  21    Post.create(params)
  22    redirect "/"
  23  end
  24  
  25  __END__
  26  @@ index
  27  %h1 Hello, Sinatra!
  28  %ul
  29    - @posts.each do |post|
  30      %li= post.content
  31  %form{:method => :post}
  32    %textarea{:name => :content}
  33    %input{:type => :submit, :value => "Post"}

config.ru

   1  require "blog.rb"
   2  run Sinatra::Application

ローカルで起動するには

   1  % ruby blog.rb

もしくは

   1  % rack

でok. rubyの場合はhttp://localhost:4567、Rackの場合は http://localhost:9292 にアクセス。

これをHerokuにデプロイすると、 http://sinatora-blog.heroku.com/ こんな感じで動きます。

posted by Png genki on Tue 14 Jul 2009 at 15:37 with 2 comments

Tabキーを押すと、Window上に配置されているNSViewのnextKeyViewの間を移動しますが、これを無効にするには、

  1. NSWindowのinitialFirstResponderを適当なView(contentViewなど)に設定する
  2. subviewsのnextKeyViewをself(view自身)にする

これでひとまず目的を実現できるようです。 きっともっと簡単な方法がありそうな気がするのですが、とりあえず。

posted by Png genki on Sat 11 Jul 2009 at 19:33