日々の記録。

プログラミングのメモや感じた事などを記録。

vimのメモ

vim操作を随時追加します。

テキストオブジェクトの選択

keys 内容
ip 段落
iw 単語
is

keys 内容
vipd ビジュアルモード 段落を削除する.
vipy ビジュアルモード 段落をヤンク(コピー)する.
dip 段落を削除する.
yip 段落をヤンク(コピー)する.

ファイル内の移動

keys 内容
' ' 直前のジャンプ位置に戻る
' . 直前に変更された位置

挿入モード中の文字削除

keys 内容
Ctrl+h 直前の1文字削除
Ctrl+w 直前の1単語削除
Ctrl+u 行頭まで削除

※ シェルでも利用可能な模様。

挿入

keys 内容
Shift+i 行頭(^)に移動して、挿入モード
Shift+a 行末($)に移動して、挿入モード

※Shift+iは行の先頭文字に移動する。(^i) 探しているのは0i...

コマンド

keys 内容
:e! 編集した内容を破棄して、開き直す

置換

:範囲s /検索パターン/置換文字列/オプション

範囲

keys 内容
(無指定) 当該行のみ対象
% ファイル全体を対象

:s /error/result/ # 当該行の最初のerrorをresultに置換する
:%s /error/result/g # ファイル全体のerrorをresultに置換する

オプション

keys 内容
選択範囲の1つのみ置換する
g 選択範囲全体を置換する
c 置換時に確認をする。

残念ながらxcodevimプラグインでは、c オプションは非対応の模様。

ペースト

keys 内容
"0p コピーした内容をペーストする。

rails modelの属性設定メソッドをオーバーライドしてみる

モデルのある属性を変更した際に、別の属性も併せて変更したかったので、モデルの属性を設定するメソッドを定義してみました。

やりたいこと。

Todoクラスに、0〜100の範囲の進捗状況という属性があって、0からの変化時に開始日を設定、 100に変化したときに終了日を設定したい。

class Todo < ActiveRecordBase
  attr_accessible :progress, :begin_date_time, :end_date_time

  #進捗を設定する.
  def progress=(val)
    now = DateTime.now
    if val > 0 and self.begin_date_time.blank?
      self.begin_date_time = now
    end
    if val == 100 and self.end_date_time.blank?
      self.end_date_time = now
    end
    #実際の属性 progressを設定する.
    write_attribute(:progress, val)
  end

属性設定(セッター)のメソッド定義

def progress=(val)

上記メソッドを定義することで、progressの設定処理を記述し、元々のprogress=をオーバーライドします。(オーバーライドという言葉は適切ではないかもしれません。)

write_attribute(:progress, val)

上記メソッドで、実際に属性progressの値を変更しています。

問題点

todoの編集画面でprogressのみ変更した場合、controller.updateの標準の動作では、 begin_date_time/end_date_timeの変更はDBに反映されません。

# todos_controller.rb 

def update
  @todo = Todo.find(params[:id])

  respond_to do |format|
    # 画面で変更された属性(paramsで設定されている属性)のみ、updateが適用される。
    #
    # 画面で進捗のみ更新した場合、メモリ上のtodoでは、progressとbegin_date_time
    #とend_date_timeの属性が更新されますが、DBへは進捗の変更しか反映されません。 
    if @todo.update_attributes(params[:todo])
      format.html { redirect_to parent_or_root_url(@todo), notice: 'Todo was     successfully updated.' }
      format.json { head :no_content }
    else
      format.html { render action: "edit" }
      format.json { render json: @todo.errors, status: :unprocessable_entity     }
    end
  end
end

対処

結局model側での開始日・終了日の設定はあきらめて、 view側で、進捗に合わせて開始日・終了日を設定するようにしました。

今後あるであろう「自動入力した値を修正したい。」という要望も考慮して・・・。

jQuery を使った要素の表示、非表示(スクロールアニメーション付き)

jQuery日本語リファレンスソースコードを参考(というか、ほぼそのまま)。 自分向けのメモとして残します。

<div id="test">test</div>
<div>
  <div>child1</div>
  <div>child2</div>
</div>
$(function() {
  $("#test").click(function() {
    var child = $(this).next();
    if( child.is(':hidden')) {
      child.slideDown('fast');
    } else {
      child.slideUp('fast');
    }
  });
});

iOS アプリがバックグランドに遷移する際の処理方法

について勉強中です。

ドキュメントより学んだ2つの方法と、1つのアイディアを紹介します。

方法1 UIApplicationDelegateのメソッドで処理する

メリット: 一カ所で処理できる。 デメリット: 処理対象のオブジェクトをUIApplicationDelegateが知る必要になり、UIApplicationDelegateがするべき処理以外もしてしまいそう。

  • バックグラウンド状態に移行時 UIApplicationDelegate applicationDidEnterBackground:メソッドにデータを保存する処理を実装する。
  • フォアグラウンドへの復帰時 UIApplicationDelegate applicationWillEnterForeground:に復元処理を実装する。

方法2 NSNotificationCenterを利用する

メリット: 処理対象のオブジェクトのみで、処理が実装できる。 デメリット: 各々のオブジェクトでNotificationの登録、削除を行うので、全体としての管理が大変。

NSNotificationCenterの使い方はここから

  • バックグランド時 UIApplicationDidEnterBackgroundNotification
  • 復帰時 UIApplicationWillEnterForegroundNotification

アイディア方法 StateChangeableというプロトコル

クラス図でのイメージはこんな感じ

f:id:hmu29:20131221134027p:plain

StateChangeableというプロトコルで、applicationDidEnterBackground・ applicationWillEnterForegroundのメソッドを定義します。そして、状態遷移を処理したいオブジェクトで、このプロトコルを実装します。アクティブなStateChangeableオブジェクトをUIApplicationDelegateに登録し、実際にUIAppliationDelegateのapplicationDidEnterBackground・ applicationWillEnterForegroundが呼び出された際には、StateChangeableオブジェクトに処理を委譲という方法です。

公式ドキュメント iOS App Programming Guide App States and Multitaskingの整理

Managing App State Changes

アプリの状態の説明と状態遷移が記載されている。

iOS7 UITableViewCellAccessoryDetailDisclosureButton

iOS7では、なぜかUITableViewのUITableViewCellAccessoryDetailDisclosureButtonの表示が変更されています。

iOS6までは、次のよう>がボタンで表示されます。

f:id:hmu29:20131215154749p:plain

一方iOS7では、次のようにiボタンと>が両方表示されます。

f:id:hmu29:20131215155157p:plain

iOS7から新しくUITableViewCellAccessoryDetailButtonが追加されていますが、これはiマークのボタンのみが追加されます。(しかもiOS6以前では使えないため、デバイスのバージョン確認が必要です)

UITableViewCellAccessoryTypeのReferenceを見る限り、標準スタイルからは>ボタンのみの表示はなくなったようです。

Webメニューはなぜ左側に配置されている? (身体的機能と文字の並びとシェードネグレクト)

 先日飲みの席で、先輩が「Webのメニューはなぜ左側か?」という問いを出しました。その問いが興味深かったので、まとめてみました。

身体的機能による説

「右手を前に出した状態(ちょうどマウスを握った状態)では、顔は左側は向けやすいけど、右側に向けづらいから。だから見やすい位置に、大切な要素を配置している」

 上記の問いに対する先輩の回答がこれでした。

 この説に科学的な根拠があるのかは不明ですが、実際に試すと、確かに右手を前に出すと右側は向けづらいような・・・。しかしディスプレイを見るときに、そこまで首を右に振ることは無いのではないかと、半信半疑で聞いていました。

言語の特性による説

 「英語の並び順。左から右に読むのが自然だから」

その場で思いついた私の回答です。

この説を裏付けるために、世界各国のWebデザインと日本のWebデザインの特徴というサイトで英語、日本語、アラビア語のWebレイアウトを比較してみました。

 英語、日本語(横書き)は画面上部か左にメニューがあるものが大半で、左から右へ目線が移動するのですが、文字を右から左へ読むアラビア語のサイトでは、英語とは対象的に、右にメニュー、真ん中にメインコンテンツが配置されているようです。やはり文字の並び順は多分にレイアウトに影響していそうです。

シェードネグレクト。脳は左側を重視する

人は左側の視野を重要視する。

 もう一つ左側にメニューがある理由として思いついたのが「シェードネグレクト」という現象です。シェードネグレクトとは、脳科学(心理学?)の言葉で、「人は左側の視野に注意が行きやすいという現象」の事です。

 池谷祐二先生の「脳には妙な癖がある」という本で紹介されていたのですが、左半分が笑顔、右半分が暗い顔と左半分が暗い顔、右半分が笑顔という絵を被験者に見せ、どちらがより笑顔に見えるかと実験したところ、左半分が笑顔の方が、笑顔であると認識する率が高いそうです。

※ シェードネグレクトについては、池谷先生の記事がWebに掲載されていました。脳は左側を重視する

まとめ

「Webメニューはなぜ左側か?」という問いには、様々な理由が考えられ、「これっ」という答えは導く事は難しいと思いますが、このような「何気ないことに問いを立てた」という事自体が面白いと思い、あれこれ思索してみました。

おまけ シェードネグレクトと身体的機能の関係

脳は左側を重視するの記事を読むと、シェードネグレクトの原因はまだ解明されてないようですが、左視野を重視するのは右利きの人が大半との事で、聞き手と関連があるそうです。素人考えですが、もしかしたらシェードネグレクトは、「右手を前に出すと右を向きづらい」という身体的特性と関連があるのかもしれません。

osx mavericks Java7でEclipse Keplerを動かす

osx mavericksでJava7をインストールして、FinderからEclipseを起動しようとするとJRE6が必要と言われて起動できません。(なぜかターミナルから直接実行する場合はできます。)

launchd.confに環境変数JAVA_HOMEやPATHを追加してみても解決しませんでしたが、次の記事を試したら動作しました。http://olarila.com/forum/viewtopic.php?f=27&t=3438

方法は、インストールしたJDKにあるInfo.plist(私の環境では/Library/Java/JavaVirtualMachines/jdk1.7.0_45.jdk/Contents/Info.plist)を次のように変更します。

変更前

<key>JVMCapabilities</key>
  <array>
    <string>CommandLine</string>
  </array>

変更後

<key>JVMCapabilities</key>
  <array>
    <string>CommandLine</string>
    <string>BundledApp</string>
    <string>WebStart</string>
    <string>Applets</string>
    <string>JNI</string>
  </array>

念のため再起動をします。私の環境では、これで「JRE6が必要」と言われなくなりました。

JVMCapabilitiesで、jvmが有効なコンテキストを設定している模様ですが、詳細は見つかっていません。。。


余談ですが、JAVA HOMEパスはxcode toolsをインストールしていれば、java_homeコマンドで簡単に取得できます。