是非に及ばず

プログラミングに関する話題などを書いていきます(主にRailsやAndroidアプリ開発について)

vim7.4でファイルを開いた時に先頭文字が「g」に置き換わる不具合の対処方法

CentOS7(64bit)でvim7.4を使ってみようと思い、最新のパッチ(764)を適用した上でビルドしたところ、タイトル通りの不具合が発生した。
2015/07/03時点では、ネットで同様の現象について書かれている記事を見つける事ができなかったので自分で書いておく。

自分はいつもTeraTermsshでサーバに接続してvimを使っているのだが、この場合にこの問題が起きるようだ。

原因は不明だが、~/.vimrcが存在していると、たとえ~/.vimrcの中身が空であろうと、任意のファイルを開いた時に先頭の文字が「g」に置き換わってしまう。
vimにおいて.vimrcを使わないという選択肢はあり得ないので、この問題は放置できない。

パッチを適用しない状態でビルドした場合は、正常に動作する事から特定のパッチを適用した場合にこの現象が起きると思われる。

763、762、...、756という感じで1つずつ適用するパッチを減らしてビルドして動作確認を行った結果、756までは問題ない事が分かった。
つまり、パッチ757でこの問題が挿入されてしまったようだ。

結論としては、しばらくはvim7.4を自前でビルドして使いたい場合は、適用するパッチは756までにするという事にした。

追記

7.4.757のパッチのコメントを見ると、
「cannot detect the background color of a terminal」
と書いてあり、背景色に関わる何かであるように思われる。
いろいろググったところ、.vimrcにset background=darkを指定する(lightでも可)と良いというツイートを発見した。
実際に、.vimrcにset background=darkを追記してファイルを開いたところ、先頭文字がgに置き換わる問題が起きなかった。
最新パッチを使いたい場合は、この方法しかなさそうだ。

追記(7/8)

7.4.766にてこの問題が修正されたように思えたのだが、自分の環境では問題が解決しなかった。
「7.4.766 (after 7.4.757) bg color check does not work on Tera Term」

自分が使っているTeraTermが最新版ではなかったので、試しに最新版の4.87にして試したところ現象が起きなくなった。

TeraTerm4.87+パッチ766以降であれば問題が起きないという事で良さそうだ。

「通信の最適化」の回避策について考える

各キャリアが行っている「通信の最適化」が問題になっているが、これをアプリやAPIなどで回避する方法をまとめる。
以下のいずれかで回避できるはず。

(1) HTTPS(SSL)を利用する
(2) 暗号化した上でデータを送受信する

HTTPS(SSL)を利用する

docomoauのページでは、SSLでは最適化は行わないと書いてあるので、これがもっとも簡単で確実な方法だろう。

暗号化した上でデータを送受信する

何らかの事情でSSLが使えないという事もあるかもしれないので、自前で暗号化する方法を提案する。
「通信の最適化」は、特定のContent-Typeのデータに適用されると推測できるので、暗号化してしまえばキャリア側の処理対象から外れるはずである。
AESなどで暗号化するライブラリはgithubですぐに見つけることが出来るし、ちょっと検索すればブログなどの記事でも見つけられる。
サーバサイドとクライアントの開発言語が異なる場合は、相互に暗号化、復号化できる実装を確認する必要がある。

ruby2.2でkyotocabinet-rubyがインストールできない問題の対処法

通常の流れとしては、
ruby extconf.rb
make
make install
で良いはずなのだが、ruby2.2で試したところエラーが発生した。

具体的なエラーはこのようなもの。

$ wget http://fallabs.com/kyotocabinet/rubypkg/kyotocabinet-ruby-1.32.tar.gz
$ tar xvzf kyotocabinet-ruby-1.32.tar.gz
$ cd  kyotocabinet-ruby-1.32
$ ruby extconf.rb

*** extconf.rb failed ***
Could not create Makefile due to some reason, probably lack of necessary
libraries and/or headers.  Check the mkmf.log file for more details.  You may
need configuration options.

Provided configuration options:
        --with-opt-dir
        --without-opt-dir
        --with-opt-include
        --without-opt-include=${opt-dir}/include
        --with-opt-lib
        --without-opt-lib=${opt-dir}/lib
        --with-make-prog
        --without-make-prog
        --srcdir=.
        --curdir
        --ruby=/home/watanabe/.rbenv/versions/2.2.2/bin/$(RUBY_BASE_NAME)
        --with-kyotocabinet-dir
        --without-kyotocabinet-dir
        --with-kyotocabinet-include
        --without-kyotocabinet-include=${kyotocabinet-dir}/include
        --with-kyotocabinet-lib
        --without-kyotocabinet-lib=${kyotocabinet-dir}/lib
extconf.rb:18:in `<main>': uninitialized constant Config (NameError)

exitconf.rbのConfigという定数というかクラスが未定義という事でエラーになっている。
Configが使われている場所を調べる。

$ grep Config extconf.rb
Config::CONFIG["CPP"] = "g++ -E"

ruby2.2ではConfigがRbConfigに変わっているので、ここを書き換えれば良いはず。

$ cp -a extconf.rb extconf.rb.bak
$ sed -i 's/Config/RbConfig/g' extconf.rb
$ diff extconf.rb extconf.rb.bak
18c18
< RbConfig::CONFIG["CPP"] = "g++ -E"
---
> Config::CONFIG["CPP"] = "g++ -E"

再度、extconf.rbを実行すると無事成功!

$ ruby extconf.rb
setting variables ...
  $CFLAGS = -I. -I/usr/local/include -Wall $(cflags) -O2
  $LDFLAGS = -L. -L/home/watanabe/.rbenv/versions/2.2.2/lib  -fstack-protector -rdynamic -Wl,-export-dynamic -L. -L/usr/local/lib
  $libs =  -lkyotocabinet -lz -lstdc++ -lrt -lpthread -lm -lc
checking for kccommon.h... yes
creating Makefile

次にmakeを実行すると、またしてもエラー・・・。

$ make
compiling kyotocabinet.cc
kyotocabinet.cc: In static member function ‘static void NativeFunction::execute(NativeFunction*)’:
kyotocabinet.cc:602: error: ‘rb_thread_blocking_region’ was not declared in this scope
make: *** [kyotocabinet.o] Error 1

ネットで調べたところ、rb_thread_blocking_regionという関数がなくなったから起きているらしい。

kyotocabinet.ccの該当行は以下のようになっている。

600   static void execute(NativeFunction* func) {
601 #if defined(_KC_YARV_)
602     rb_thread_blocking_region(execute_impl, func, RUBY_UBF_IO, NULL);
603 #else
604     func->operate();
605 #endif
606   }

_KC_YARV_が定義されていたらrb_thread_blocking_regionを使用するという事になっているが、
代替手段としてfunc->operate()が用意されている。
という事は、常にfunc->operate()を使うようにしてやれば良いはず。

調べたところ、_KC_YARV_ は601~605行目の処理のみで利用されているので影響範囲が小さい。

24 #if RUBY_VM >= 1
25 #define _KC_YARV_
26 #endif

とりあえず、25行目を空にしてやれば良いだろう。

$ cp -a kyotocabinet.cc kyotocabinet.cc.bak
$ sed -i 's/define _KC_YARV_//g' kyotocabinet.cc
$ diff kyotocabinet.cc kyotocabinet.cc.bak
25c25
< #
---
> #define _KC_YARV_

再度、makeを実行するとエラーが起きずにコンパイルが成功した。

$ make
compiling kyotocabinet.cc
linking shared-object kyotocabinet.so

とりあえず、インストールする。

$ make install

テストを実行して問題がないか確認するが、やっぱりエラー。

$ ruby test.rb
test.rb:33:in `<main>': uninitialized constant Config (NameError)

例によってConfigをRbConfigにしてやれば良い。

影響範囲を調べる。なぜかRbConfigに直ってるやつもある・・・
$ grep Config test.rb
rubycmd = Config::CONFIG["bindir"] + "/" + RbConfig::CONFIG['ruby_install_name']

$ cp -a test.rb test.rb.bak
$ sed -i 's/rubycmd = Config/rubycmd = RbConfig/' test.rb
$ diff test.rb test.rb.bak
33c33
< rubycmd = RbConfig::CONFIG["bindir"] + "/" + RbConfig::CONFIG['ruby_install_name']
---
> rubycmd = Config::CONFIG["bindir"] + "/" + RbConfig::CONFIG['ruby_install_name']

再度、テストを実行(少し時間かかる)すると、無事に全てのテストが成功。

$ ruby test.rb
001/105: kctest.rb order ':' '10000': ok
002/105: kctest.rb order -rnd ':' '10000': ok
003/105: kctest.rb order -etc ':' '10000': ok
...
105/105: kctest.rb misc 'casket.kcf': ok
105 tests were all ok

これで安心してruby2.2でもkyotocabinetを使う事が出来る。

jpmobileでundefined method `extract_handler_and_format_and_variant'という例外が発生する場合の対処方法

rails 4.0.8とjpmobile 4.1.2の組み合わせで以下のような例外が発生するようになった。

undefined method `extract_handler_and_format_and_variant' for #<Jpmobile::Resolver:0x007fc644bf8350>

解決したので書いておく。

エラーの原因

Jpmobile::ResolverはActionViewのextract_handler_and_format_and_variantを利用しているのだが、undefined methodという事でこのメソッドがなくなってしまったようだ。
extract_handler_and_formatという似た名前のメソッドを見つけたので、これ使えばいいんじゃね?という適当な理由で試してみた。
無事動いたので、一時しのぎ的な対応としては十分だろう。

具体的な対処方法

このファイルを作ってRailsを再起動すれば解決した。
config/initializers/jpmobile_resolver_patch.rb

class Jpmobile::Resolver
  def extract_handler_and_format_and_variant(template, formats)
    extract_handler_and_format(template, formats)
  end
end

これで問題なく動いているが本当にこれで正しいのかは分からない。

データ構造とコードはどちらも重要である

こんな記事を見たので思うところを書いてみる。
【コンピュータサイエンス名言紹介 vol.1】Linus Torvaldsの考える「良いプログラマーが気にかけること」

この記事の中でポイントとなるのは、
「ダメなプログラマーはコードに気をつかう。良いプログラマーはデータ構造とそれらの関係に気をつかう。」
というところだろう。
おっしゃる事には同意するのだが、こういう強めの主張はグサッと心に刺さる反面、データ構造にさえ気を付ければ、どんなダメなコードを書いても良いプログラマなのだという誤解を招きかねないという心配をしてしまう。

上記の主張をされているのは、言うまでもなく経験の豊富な優れたプログラマーであり、きちんとしたコードを書ける人である。
きちんとしたコードが書けるという前提の元で、コードよりデータ構造のほうが大切なんだという事を言っているのであって、きちんとしたコードも書けないような人がデータ構造のほうが大切だとか抜かすのは大きな間違いであると思う。
自分自身も含めた一般的なレベルのプログラマは、データ構造もコードも大切だと考えるべきであると主張したい。
良いコードを書くにどうすればいいのか、良い設計とはどんな物なのかという事を常に気に掛けてレベルアップしていきたい。

jpmobileをTizenに対応させる方法(Rails3)

概要

jpmobileをTizenに対応させてみる を参考にしたというかほぼそのまま。
参考サイトでは、lib/以下にファイルを置いているけど、個人的には独自のパッチは、config/initializers/以下に配置するのがベストだと思うので、そっちのアプローチで対応してみた。

ソース

以下のソースをconfig/initializers/jpmobile_tizen.rbとして保存して、railsを再起動すれば完了!

# encoding: utf-8
#
#== 概要
# jpmobileをTizeに対応させるパッチ
module Jpmobile

  module Mobile
    DEFAULT_CARRIERS_WITH_TIZEN = DEFAULT_CARRIERS + ["Tizen"]
    def self.carriers
      if @carriers.nil? || @carriers == DEFAULT_CARRIERS
        @carriers = DEFAULT_CARRIERS_WITH_TIZEN.dup
      end
      @carriers
    end

    class Tizen < SmartPhone
      # 対応するUser-Agentの正規表現
      USER_AGENT_REGEXP = /Tizen/
    end
  end

end

できるようになる事

ユーザエージェントにTizenを含む端末に対して以下の動作は確認できた。

  • request.smart_phone?がtrueになる
  • app/views/xxx_smart_phone.html.erb などスマートフォン用のビューが参照される

Node.jsをCentOS5.xにインストールする手順

node.jsをCentOS5.xにインストールする手順のメモ。

検証環境と前提

CentOS 5.8 64bit
Node.js 0.98
Python 2.7.3

インストール手順

最新のPythonをインストール

CentOS 5.8の標準で入るPyhtonのバージョンは、2.4.3となっているが、 Node.jsのビルドでは、2.6以上が必要なのでそのままではうまく行かない。
そこで、Python公式サイトから最新のソースをダウンロードしてビルドする事にする。
ただし、/usr/localなど標準で参照されるパスに入れてしまうと、CentOSの他のツールなどと競合して問題になる。 そこで、$HOME/local以下にインストールする事で影響が出ないようにする。

$ mkdir -p ~/download
$ mkdir -p ~/build
$ cd ~/download
$ wget http://www.python.org/ftp/python/2.7.3/Python-2.7.3.tgz
$ cd ../build/
$ tar xvzf ../download/Python-2.7.3.tgz
$ cd Python-2.7.3
$ sudo yum install bzip2-devel -y
$ ./configure --prefix=$HOME/local/python-2.7.3
$ make
$ make install
$ ln -s $HOME/local/python-2.7.3 $HOME/local/python

.bash_profileのPATHに$HOME/local/python/binを追加する。

$ source ~/.bash_profile
$ python -V
Python 2.7.3

Node.jsをインストール

$ cd ~/download
$ wget http://nodejs.org/dist/v0.8.9/node-v0.8.9.tar.gz
$ cd ../build
$ tar xvzf ../download/node-v0.8.9.tar.gz
$ cd node-v0.8.9/
$ ./configure --prefix=$HOME/local/node-v0.8.9
$ make
$ make install

$HOME/local/node-v0.8.9/binをPATHに追加

$ source ~/.bash_profile
$ node -v
v0.8.9

以上で導入は完了。
jsdomはほとんどの場合で必要になるので、ついでに入れておく。

$ npm install -g jsdom

さらにTypeScriptも入れておく。
npmのパッケージとして提供されているのですぐに利用できる。

$ npm install -g typescript