Hatena::Groupkeysnail

basyura snail

2011-02-06

るりまサーチで更に早く検索する

| 19:50 |  るりまサーチで更に早く検索する - basyura snail を含むブックマーク はてなブックマーク -  るりまサーチで更に早く検索する - basyura snail

みんな大好き Ruby のリファレンス検索サービス「るりまサーチ(最速Rubyリファレンスマニュアル検索!)」を使ってサクっと検索する。

プロンプトを立ちあげて入力

shell: rurema 検索する単語

f:id:basyura:20110206193455p:image

Enter で検索

f:id:basyura:20110206193456p:image

以下を keysnail の設定ファイに書く。

key.setGlobalKey(['C-x','C-r'], function (ev, arg) {
    shell.input("rurema ");
  });
shell.add("rurema" , M({ja: "るりまサーチ", en: "rurema search"}) ,
  function(argx , extra) {
    let url  = "http://doc.ruby-lang.org/ja/search/version:1.9.2/";
    let list = extra.left.split(/\s+/)
    for(let i = 0 ; i < list.length ; i++) {
      url += 'query:' + encodeURIComponent(list[i]) + '/';
    }
    gBrowser.loadOneTab(url, null, null, null, extra.bang);
  },
  {
    bang      : true,
    literal   : 0,
    completer : function (args, extra) {
      let engines = [util.suggest.ss.getEngineByName("Google")];
      return completer.fetch.suggest(engines, true)(extra.left || "", extra.whole || "");
    },
  },
  true);

ショートカットキーを指定しておけばさらに早く!(ここでは C-x C-r で定義)

関係ないけど for 文をもうちょっとカッコよく書けないものか。

moozmooz2011/02/12 22:29おお,これは便利ですね.早速登録しました.

>関係ないけど for 文をもうちょっとカッコよく書けないものか。

カッコ良いかは分かりませんが,次のような書き方もできますね.多少 Ruby っぽいかと思います.

url += extra.left.split(/\s+/)
.map(function (q) "query:" + encodeURIComponent(q) + "/")
.join("");

basyurabasyura2011/02/13 18:31map ですか!
勉強になります。

トラックバック - http://keysnail.g.hatena.ne.jp/basyura/20110206

2010-03-28

Ruby API 検索 その3 - メソッドも補完

| 22:07 |  Ruby API 検索 その3 - メソッドも補完 - basyura snail を含むブックマーク はてなブックマーク -  Ruby API 検索 その3 - メソッドも補完 - basyura snail

最初はクラス名を補完。# を入力した後はそのクラスのインスタンスメソッドを補完。

補完用ファイルをゴリッと作ったらサイズがでかくなったので、テキストファイルサーバに置いておいて XMLHttpRequest で取得するように修正。

微妙にファイルサイズがでかいので、キャッシュして持っておくのもなんだなぁと思うので、ウイークリファレンス的なことをしたいんだけど無理?。リファレンスページを開いた時点で変数(ruby_completes)に null を突っ込んでもいいけど、このメモリってちゃんと回収されるんだろうか?定義ファイルを読み込み直した時点で null で初期化されるけど。

サーバRuby で補完候補を都度作って通信してもいいけど、Ruby のバージョン分沢山用意するのもめんどい。速度はそんなに遅くないと思うけど試してない。

リファレンスページのヒット率が高いのか低いのかが謎 (><)

let ruby_completes = null;
shell.add("refe" , M({ja: "Ruby リファレンス検索", en: "ruby reference search"}) ,
  function (args, extra) {
    function generate_url(word) {
      let site   = "http://doc.okkez.net/188";
      let clazz  = word.split("#")[0];
      let method = word.split("#")[1];
      //let clazz  = word.split("\.")[0];
      //let method = word.split("\.")[1];
      // not match. search by google with site: .
      if(ruby_completes["classes"].indexOf(clazz) == -1) {
        let w = encodeURIComponent(word + " site:" + site);
        return "http://www.google.co.jp/search?q=" + w + "&ie=utf-8&oe=utf-8";
      }
      // no method. open clazz's
      if(method == undefined) {
        return site + "/view/class/" + clazz;
      }
      // try to find clazz's method
      let url = site + "/view/method/" + clazz + "/i/" + encode_method(method);
      if(isAvailable(url)) {
        return url;
      }
      // try to find object's method
      url = site + "/view/method/Object/i/" + encode_method(method);
      if(isAvailable(url)) {
        return url;
      }
      /*
      // try to find singleton's method
      url = site + "/view/method/" + clazz + "/s/" + encode_method(method);
      if(isAvailable(url)) {
        return url;
      }
      // try to find module's method
      url = site + "/view/method/" + clazz + "/m/" + encode_method(method);
      if(isAvailable(url)) {
        return url;
      }
      // try to find special method
      url = site + "/view/method/" + clazz + "/v/" + encode_method(method);
      if(isAvailable(url)) {
        return url;
      }
      // try to find const
      url = site + "/view/method/" + clazz + "/c/" + encode_method(method);
      if(isAvailable(url)) {
        return url;
      }
      */
      // open clazz's 
      return site + "/view/class/" + clazz;
    }
    function isAvailable(url) {
      var http = new XMLHttpRequest();
      http.open("HEAD" , url , false);
      http.setRequestHeader("accept-language" , "ja");
      http.setRequestHeader("Cache-Control"   , "no-cache");
      http.setRequestHeader("content-type"    , "application/x-www-form-urlencoded");
      http.send();
      return http.status == 200;
    }
    function encode_method(method) {
      return encodeURIComponent(method).replace("%","=");
    }
    // open tab
    let url = generate_url(extra.left)
    gBrowser.loadOneTab(url, null, null, null, extra.bang);
  },
  {
    bang      : true,
    literal   : 0,
    completer : function (args, extra) {
    function get_completes() {
      var http = new XMLHttpRequest();
      http.open("GET" , "http://basyura.org/ruby_completes/1.8.8.txt" , false);
      http.setRequestHeader("accept-language" , "ja");
      http.setRequestHeader("Cache-Control"   , "no-cache");
      http.setRequestHeader("content-type"    , "application/x-www-form-urlencoded");
      http.send();
      return http.responseText;
    }
    if (ruby_completes == null) {
      ruby_completes = eval("(" + get_completes() + ")");
    }
    if(extra.left.indexOf("#") != -1) {
      let clazz = extra.left.split("#")[0];
      let list  = ruby_completes[clazz];
      if(list != undefined) {
            return completer.matcher.substring(list)(extra.left || "");
      }
    }
      return completer.matcher.substring(ruby_completes["classes"])(extra.left || "");
    }
  },
  true
);

補完用ファイルはこんな感じ。

{
"classes":["Array" , "String" , ...],
"Array":["Array#find" , "Array#inspect" , ...],
"String":["String#upcase!" , "String#zip" , ...], 
・・・
}
トラックバック - http://keysnail.g.hatena.ne.jp/basyura/20100328

2010-03-26

Ruby API 検索 - その2

| 21:19 |  Ruby API 検索 - その2 - basyura snail を含むブックマーク はてなブックマーク -  Ruby API 検索 - その2 - basyura snail

メソッドも指定できるようにしたい。でも、補完用の設定をたくさん用意するのも嫌だ(めんどくさい)。てことで、可能な限り見つけられるようにしてみた。

refe String#to_s

と「#」で区切るとメソッドのリファレンスページを直接開くようにトライする。該当のページが存在するかは HTTP ヘッダのステータスを見る。200 で無い場合ば次をチェックする。

Clazz#method → Object#method → Kernel#method 
→ Module#method → Kernel#method(特殊メソッド) → Kernel#method(定数) 
→ Clazz

といった順番に検索される(はず)だけど、さすがに全部スルーして結局クラスのページを開く場合は遅い。Object#method までで十分じゃないかと思うのでコメントアウト

let ruby_completes = [
"ARGF","Array","Bignum","Binding","Class","Comparable","Continuation","Data","Dir",
"ENV","Enumerable","Enumerator","Errno","FalseClass",
"File","File::Constants","File::Stat","FileTest","Fixnum","Float","GC","Hash","IO","Integer",
"Kernel","Marshal","MatchData","Math","Method","Module","NilClass","Numeric","Object",
"ObjectSpace","Precision","Proc","Process","Process::GID","Process::Status",
"Process::Sys","Process::UID","Range","Regexp","Signal",
"String","Struct","Struct::Tms","Symbol","Thread","ThreadGroup","Time","TrueClass",
"UnboundMethod","ArgumentError","EOFError","Errno::E2BIG","Errno::EACCES","Errno::EADDRINUSE",
"Errno::EADDRNOTAVAIL","Errno::EADV","Errno::EAFNOSUPPORT","Errno::EAGAIN","Errno::EALREADY",
"Errno::EBADE","Errno::EBADF","Errno::EBADFD","Errno::EBADMSG","Errno::EBADR","Errno::EBADRQC",
"Errno::EBADSLT","Errno::EBFONT","Errno::EBUSY","Errno::ECHILD","Errno::ECHRNG","Errno::ECOMM",
"Errno::ECONNABORTED","Errno::ECONNREFUSED","Errno::ECONNRESET","Errno::EDEADLK","Errno::EDEADLOCK",
"Errno::EDESTADDRREQ","Errno::EDOM","Errno::EDOTDOT","Errno::EDQUOT","Errno::EEXIST","Errno::EFAULT",
"Errno::EFBIG","Errno::EHOSTDOWN","Errno::EHOSTUNREACH","Errno::EIDRM","Errno::EILSEQ",
"Errno::EINPROGRESS","Errno::EINTR","Errno::EINVAL","Errno::EIO","Errno::EISCONN","Errno::EISDIR",
"Errno::EISNAM","Errno::EL2HLT","Errno::EL2NSYNC","Errno::EL3HLT","Errno::EL3RST","Errno::ELIBACC",
"Errno::ELIBBAD","Errno::ELIBEXEC","Errno::ELIBMAX","Errno::ELIBSCN","Errno::ELNRNG","Errno::ELOOP",
"Errno::EMFILE","Errno::EMLINK","Errno::EMSGSIZE","Errno::EMULTIHOP","Errno::ENAMETOOLONG",
"Errno::ENAVAIL","Errno::ENETDOWN","Errno::ENETRESET","Errno::ENETUNREACH","Errno::ENFILE",
"Errno::ENOANO","Errno::ENOBUFS","Errno::ENOCSI","Errno::ENODATA","Errno::ENODEV","Errno::ENOENT",
"Errno::ENOEXEC","Errno::ENOLCK","Errno::ENOLINK","Errno::ENOMEM","Errno::ENOMSG","Errno::ENONET",
"Errno::ENOPKG","Errno::ENOPROTOOPT","Errno::ENOSPC","Errno::ENOSR","Errno::ENOSTR","Errno::ENOSYS",
"Errno::ENOTBLK","Errno::ENOTCONN","Errno::ENOTDIR","Errno::ENOTEMPTY","Errno::ENOTNAM","Errno::ENOTSOCK",
"Errno::ENOTTY","Errno::ENOTUNIQ","Errno::ENXIO","Errno::EOPNOTSUPP","Errno::EOVERFLOW","Errno::EPERM",
"Errno::EPFNOSUPPORT","Errno::EPIPE","Errno::EPROTO","Errno::EPROTONOSUPPORT","Errno::EPROTOTYPE",
"Errno::ERANGE","Errno::EREMCHG","Errno::EREMOTE","Errno::EREMOTEIO","Errno::ERESTART","Errno::EROFS",
"Errno::ERROR","Errno::ESHUTDOWN","Errno::ESOCKTNOSUPPORT","Errno::ESPIPE","Errno::ESRCH","Errno::ESRMNT",
"Errno::ESTALE","Errno::ESTRPIPE","Errno::ETIME","Errno::ETIMEDOUT","Errno::ETOOMANYREFS",
"Errno::ETXTBSY","Errno::EUCLEAN","Errno::EUNATCH","Errno::EUSERS","Errno::EWOULDBLOCK","Errno::EXDEV",
"Errno::EXFULL","Errno::EXXX","Exception","FloatDomainError","IOError","IndexError","Interrupt",
"LoadError","LocalJumpError","NameError","NoMemoryError","NoMethodError","NotImplementedError",
"RangeError","RegexpError","RuntimeError","ScriptError","SecurityError","SignalException",
"StandardError","StopIteration","SyntaxError","SystemCallError","SystemExit","SystemStackError",
"ThreadError","TypeError","ZeroDivisionError","fatal"];

shell.add("refe" , M({ja: "Ruby リファレンス検索", en: "ruby reference search"}) ,
  function (args, extra) {
    function generate_url(word) {
      let site   = "http://doc.okkez.net/188";
      let clazz  = word.split("#")[0];
      let method = word.split("#")[1];
      // not match. search by google with site: .
      if(ruby_completes.indexOf(clazz) == -1) {
        let w = encodeURIComponent(word + " site:" + site);
        return "http://www.google.co.jp/search?q=" + w + "&ie=utf-8&oe=utf-8";
      }
      // no method. open clazz's
      if(method == undefined) {
        return site + "/view/class/" + clazz;
      }
      // try to find clazz's method
      let url = site + "/view/method/" + clazz + "/i/" + encode_method(method);
      if(isAvailable(url)) {
        return url;
      }
      // try to find object's method
      url = site + "/view/method/Object/i/" + encode_method(method);
      if(isAvailable(url)) {
        return url;
      }
      /*
      // try to find singleton's method
      url = site + "/view/method/" + clazz + "/s/" + encode_method(method);
      if(isAvailable(url)) {
        return url;
      }
      // try to find module's method
      url = site + "/view/method/" + clazz + "/m/" + encode_method(method);
      if(isAvailable(url)) {
        return url;
      }
      // try to find special method
      url = site + "/view/method/" + clazz + "/v/" + encode_method(method);
      if(isAvailable(url)) {
        return url;
      }
      // try to find const
      url = site + "/view/method/" + clazz + "/c/" + encode_method(method);
      if(isAvailable(url)) {
        return url;
      }
      */
      // open clazz's 
      return site + "/view/class/" + clazz;
    }
    function isAvailable(url) {
      var http = new XMLHttpRequest();
      http.open("HEAD" , url , false);
      http.setRequestHeader("accept-language" , "ja");
      http.setRequestHeader("Cache-Control"   , "no-cache");
      http.setRequestHeader("content-type"    , "application/x-www-form-urlencoded");
      http.send();
      return http.status == 200;
    }
    function encode_method(method) {
      return encodeURIComponent(method).replace("%","=");
    }
    // open tab
    let url = generate_url(extra.left)
    gBrowser.loadOneTab(url, null, null, null, extra.bang);
  },
  {
    bang      : true,
    literal   : 0,
    completer : function (args, extra) {
      return completer.matcher.substring(ruby_completes)(extra.left || "");
    }
  },
  true
);

追記

「#」だと打ちにくいから

let clazz  = word.split("\.")[0];
let method = word.split("\.")[1];

として「.」で判定した方がいいのかも。

トラックバック - http://keysnail.g.hatena.ne.jp/basyura/20100326

2010-03-25

Ruby API 検索

| 22:27 |  Ruby API 検索 - basyura snail を含むブックマーク はてなブックマーク -  Ruby API 検索 - basyura snail

存在するクラスの場合は直接リファレンスページを開き、無い場合はグーグルでサイト検索する。

こうですか (> <)

f:id:basyura:20100325222151p:image

let ruby_completes = [
"ARGF","Array","Bignum","Binding","Class","Comparable","Continuation","Data","Dir",
"ENV","Enumerable","Enumerator","Errno","FalseClass",
"File","File::Constants","File::Stat","FileTest","Fixnum","Float","GC","Hash","IO","Integer",
"Kernel","Marshal","MatchData","Math","Method","Module","NilClass","Numeric","Object",
"ObjectSpace","Precision","Proc","Process","Process::GID","Process::Status",
"Process::Sys","Process::UID","Range","Regexp","Signal",
"String","Struct","Struct::Tms","Symbol","Thread","ThreadGroup","Time","TrueClass",
"UnboundMethod","ArgumentError","EOFError","Errno::E2BIG","Errno::EACCES","Errno::EADDRINUSE",
"Errno::EADDRNOTAVAIL","Errno::EADV","Errno::EAFNOSUPPORT","Errno::EAGAIN","Errno::EALREADY",
"Errno::EBADE","Errno::EBADF","Errno::EBADFD","Errno::EBADMSG","Errno::EBADR","Errno::EBADRQC",
"Errno::EBADSLT","Errno::EBFONT","Errno::EBUSY","Errno::ECHILD","Errno::ECHRNG","Errno::ECOMM",
"Errno::ECONNABORTED","Errno::ECONNREFUSED","Errno::ECONNRESET","Errno::EDEADLK","Errno::EDEADLOCK",
"Errno::EDESTADDRREQ","Errno::EDOM","Errno::EDOTDOT","Errno::EDQUOT","Errno::EEXIST","Errno::EFAULT",
"Errno::EFBIG","Errno::EHOSTDOWN","Errno::EHOSTUNREACH","Errno::EIDRM","Errno::EILSEQ",
"Errno::EINPROGRESS","Errno::EINTR","Errno::EINVAL","Errno::EIO","Errno::EISCONN","Errno::EISDIR",
"Errno::EISNAM","Errno::EL2HLT","Errno::EL2NSYNC","Errno::EL3HLT","Errno::EL3RST","Errno::ELIBACC",
"Errno::ELIBBAD","Errno::ELIBEXEC","Errno::ELIBMAX","Errno::ELIBSCN","Errno::ELNRNG","Errno::ELOOP",
"Errno::EMFILE","Errno::EMLINK","Errno::EMSGSIZE","Errno::EMULTIHOP","Errno::ENAMETOOLONG",
"Errno::ENAVAIL","Errno::ENETDOWN","Errno::ENETRESET","Errno::ENETUNREACH","Errno::ENFILE",
"Errno::ENOANO","Errno::ENOBUFS","Errno::ENOCSI","Errno::ENODATA","Errno::ENODEV","Errno::ENOENT",
"Errno::ENOEXEC","Errno::ENOLCK","Errno::ENOLINK","Errno::ENOMEM","Errno::ENOMSG","Errno::ENONET",
"Errno::ENOPKG","Errno::ENOPROTOOPT","Errno::ENOSPC","Errno::ENOSR","Errno::ENOSTR","Errno::ENOSYS",
"Errno::ENOTBLK","Errno::ENOTCONN","Errno::ENOTDIR","Errno::ENOTEMPTY","Errno::ENOTNAM","Errno::ENOTSOCK",
"Errno::ENOTTY","Errno::ENOTUNIQ","Errno::ENXIO","Errno::EOPNOTSUPP","Errno::EOVERFLOW","Errno::EPERM",
"Errno::EPFNOSUPPORT","Errno::EPIPE","Errno::EPROTO","Errno::EPROTONOSUPPORT","Errno::EPROTOTYPE",
"Errno::ERANGE","Errno::EREMCHG","Errno::EREMOTE","Errno::EREMOTEIO","Errno::ERESTART","Errno::EROFS",
"Errno::ERROR","Errno::ESHUTDOWN","Errno::ESOCKTNOSUPPORT","Errno::ESPIPE","Errno::ESRCH","Errno::ESRMNT",
"Errno::ESTALE","Errno::ESTRPIPE","Errno::ETIME","Errno::ETIMEDOUT","Errno::ETOOMANYREFS",
"Errno::ETXTBSY","Errno::EUCLEAN","Errno::EUNATCH","Errno::EUSERS","Errno::EWOULDBLOCK","Errno::EXDEV",
"Errno::EXFULL","Errno::EXXX","Exception","FloatDomainError","IOError","IndexError","Interrupt",
"LoadError","LocalJumpError","NameError","NoMemoryError","NoMethodError","NotImplementedError",
"RangeError","RegexpError","RuntimeError","ScriptError","SecurityError","SignalException",
"StandardError","StopIteration","SyntaxError","SystemCallError","SystemExit","SystemStackError",
"ThreadError","TypeError","ZeroDivisionError","fatal"];

shell.add("rubyapi" , M({ja: "Ruby API 検索", en: "ruby api search"}) ,
    function (args, extra) {
      let site = "http://doc.okkez.net/188";
      for(let i = 0 ; i < ruby_completes.length ; i++) {
        if(ruby_completes[i] == extra.left) {
          let url = site + "/view/class/" + extra.left;
          gBrowser.loadOneTab(url, null, null, null, extra.bang);
          return;
        }
      }
      let words = encodeURIComponent(extra.left + " site:" + site);
      let url = "http://www.google.co.jp/search?q=" + words + "&ie=utf-8&oe=utf-8";
      gBrowser.loadOneTab(url, null, null, null, extra.bang);
    },
    {
      bang      : true,
      literal   : 0,
      completer : function (args, extra) {
        return completer.matcher.substring(ruby_completes)(extra.left || "");
      }
    },
  true
);
トラックバック - http://keysnail.g.hatena.ne.jp/basyura/20100325

2010-03-24

Google でリファレンス検索

| 21:44 |  Google でリファレンス検索 - basyura snail を含むブックマーク はてなブックマーク -  Google でリファレンス検索 - basyura snail

【3/25 - ダメダメだったので修正】

shell.add の第五引数に true を設定しないと _keysnail.js を再読み込みしても反映されない。最初に書いて動いたものが動いてるのにそれに気付かずリファクタリングしていった結果がこれだよ orz

shell.add(names, description, callback, extra, replace);
    * names(Array)
          o コマンド名となる文字列の配列
    * description(String)
          o コマンドの簡易説明
    * callback(Function)
          o 実行される function オブジェクト
    * additional(Object)
          o 補完機能やコマンド引数などを格納するオブジェクト (省略可能)
    * replace(Boolean)
          o 既に存在するコマンドの場合、置き換えるか否か (省略可能)
Command System (Japanese)

site の指定も「http://doc.okkez.net/188/」に修正。



Ruby の新リファレンスマニュアル(http://doc.okkez.net/188/)。検索窓が有るんだけど検索が妙に遅いことが良くある。ヒットしない単語で検索かけちゃうと遅い気がするけどよく分からない。

遅いんだったら Google で site 使って検索すりゃいいじゃんと思いつき、そんなら keysnail からコマンドで検索できると楽でいいじゃんと思って実装してみた。

zou-search まんまだけど、コマンドと site を指定すれば他にも簡単に登録できるようにしてみた。

function defineGoogleSearchCommand(names, description , site) {
  shell.add(names , description ,
    function (args, extra) {
      let words = encodeURIComponent(extra.left + " site:" + site);
      let url = "http://www.google.co.jp/search?q=" + words + "&ie=utf-8&oe=utf-8";
      gBrowser.loadOneTab(url, null, null, null, extra.bang);
    },
    {
      bang      : true,
      literal   : 0,
      completer : function (args, extra) {
        let engines = [util.suggest.ss.getEngineByName("Google")];
        return completer.fetch.suggest(engines, true)(extra.left || "", extra.whole || "");
      },
  	},
	true);
}

defineGoogleSearchCommand(
  ["rubyapi"] , 
  M({ja: "Ruby API 検索", en: "ruby api search"}) , 
  "http://doc.okkez.net/188/"
);

わざわざプラグイン化しなくても _keysnail.js に登録すればいいのでらくちん。

補完した後に半角スペースを入れるのはできないのかな?地味にめんどくさい。

トラックバック - http://keysnail.g.hatena.ne.jp/basyura/20100324