スキマハコ

わすれがちなスキマな事を詰め込んでいます。ITの他に暮らしについても書いています。

文字から文字コードを取得しよう

1.8.xではこんな風にしてました。

    a = "ab"
    p "a=#{a[0]}"
#=>a=97

でも、これが利用できなくなりました。
原因?として、stringクラスに文字コード情報が付加したためにブロックされたのではないかなあと考えてます。
いろいろ検討した結果が以下の通り。

    a = "ab"
    p "a=#{a}"
    p "a[0]=#{a[0]}"
    p "a.ord=#{a.ord}"
    p "a[0].ord=#{a[0].ord}"
    p "a.unpack('C*')[0]=#{a.unpack('C*')[0]}"
  p "a.unpack('C')[0]=#{a.unpack('C')[0]}"
#=>"a=ab"
#=>"a[0]=a"
#=>"a.ord=97"
#=>"a[0].ord=97"
#=>"a.unpack('C*')[0]=97"
#=>"a.unpack('C')[0]=97"

1.8.xではunpack利用が推奨、1.9.xからはordが利用可能。
両方のバージョンだったら、とりあえずunpack利用しておけばいいと思われる。

また、文字の結合もきちんと明示しないとだめになったようです。

#-------------------------------1.8.x
    a = "ab"
    p "a.unpack('C*').to_s=" + a.unpack('C*').to_s
#=>"a=9798"
#-------------------------------1.9.x
    a = "ab"
    p "a.unpack('C*').to_s="+a.unpack('C*').to_s
#=>"a=["9798"]"

なんか配列になった!!!!!
ここではjoinを利用すると良さげ。
Array#join(区切り文字)は指定した区切り文字で配列を連結し、文字列を返してくれる。
指定しない場合は区切り文字なし。単純な配列の連結が可能。

#-------------------------------1.9.x
    a = "ab"
    p "a.unpack('C*').to_s="+a.unpack('C*').to_s
    p "a.unpack('C*').to_s="+a.unpack('C*').join
#=>"a=["9798"]"
#=>"a=9798"

packとunpackの使い方はマスターしたいなあ。
なんだかリファレンスだとpackで連結した文字列を返してくれそうなんだけど、気のせいかしら。

UnixTime⇔グレゴリオ暦の計算をAPIを使わずにやってみる[※未解決※]

※できてません。助けて!

そもそもUnixTimeって?

UNIX時間またはUNIX時刻(UNIX time or POSIX time)とはコンピューターシステム上で日時を表す単位。UTCでの1970年1月1日真夜中(0時0分0秒)からの経過秒数(閏秒を加味しない)で表される。
UNIX時間 - Wikipedia

1970年1月1日からの累計秒ですね!なるほど!
うるう年とかも考慮しつつ…むむむ。

先人たちの知恵を借りる。

フェアフィールドの公式
1年1月1日(0年13月1日) 〜 y 年 m 月 d の日数を求める
ツェラーの公式 - Wikipedia

よーし!これをプログラミングしたらいいんだよね!

近代の先人たちの知恵をさらに借りる

参考:
すでにプログラミングっぽく成立してる!
よーしやるぞー!と思ってそのまま実装。ほとんど式がまんまなのでコピペですね。

手近にあったrubyでやってみました。

    # グレゴリオ暦元年から現在までの経過日数を計算
    sum_day = (365.0 * year + (year / 4.0).floor  - (year / 100.0).floor   + (year / 400.0).floor   + ((306.0 * (month + 1)) / 10.0).floor + day - 428) - epoc_time
    # floorをかまさなかったらなんだか値が大幅にずれた。
    #sum_day = (365 * year + (year / 4) - (year / 100)   + (year / 400)   + (306 * ((month + 1) / 10))   - 428 + day) -  epoc_time
    # 経過日数を秒変換し、時分秒を加算
    sum_time = sum_day * 86400.0 + (hour * 3600.0) + (minute * 60.0) + second
    p "----------------------------------------"
    p "a_経過日数(1970から):" + sum_day.to_s
    p "a_経過秒(1970から):" + sum_time.to_s
    p Time.at(sum_time).utc;
    p Time.utc(year , month , day ,hour , minute , second).to_i
    p (Time.utc(year , month , day ,hour , minute , second).to_i - sum_time) / 3600
    p "----------------------------------------"

#=>
#"----------------------------------------"
#"a_経過日数(1970から):12841.0"
#"a_経過秒(1970から):1109502671.0"
#Sun Feb 27 11:11:11 UTC 2005
#1109589071
#24.0
#"----------------------------------------"

なんかずれる…。
場合によっては一致したり、1日2日のずれが発生します。
これはだめだ…orz

逆変換は月日の扱いに弱い…

   # グレゴリオ暦元年から現在までの経過秒から年月日時分秒を取得
    h = (( sum_time % 86400 ) / 3600.0).floor
    mm = ((( sum_time % 86400 ) - h * 3600.0 ) / 60.0).floor
    s = (( sum_time % 86400 ) - h * 3600 ) - mm * 60
    times = (h * 3600) + (mm * 60) + s
    # 割り切れない値をそれぞれ分配
    p h.to_s + ":" + mm.to_s + ":" + s.to_s
    days = (sum_time - times) / 86400.0
    # 1970/1/1以降の累積日数を追加する。
    days = days + epoc_time
    y = (days / 365.0).floor
    # 1年で割り切れない値を月と日のために算出(当年以外のうるう日は除く)
    uruu =  (((y-1) / 4.0).floor  - ((y-1) / 100.0).floor   + ((y-1) / 400.0).floor)
    samedays = ((days + 365 - uruu)% 365).floor 

    # 当年がうるう年の場合に備える
    jan = (y % 4 == 0 || y % 100 != 0 && y % 400 == 0) ? 29 : 28

    # 計算式が思いつかないので、地道に足していきます
    months = [31,jan,31,30,31,30,31,31,30,31,30,31]
    m = 0
    d = 0
    for i in 0...12
      if m + months[i] > samedays
        d = samedays - m
        m = i + 1
        break
      end
      m = m + months[i]
    end
    p y.to_s + "/" + m.to_s + "/" + d.to_s

うーん、一日二日ずれる…計算どっかで違うのかなー

prototype.js版のajaxできたよー

jqueryと同居できないことに注意!
jqueryを前回の記述のようにしていると、「Ajaxの型が見つかりません!」といわれてしまうのです。

  • application.js
function method(page){
    try{
	var a = new Ajax.Updater(
		"result",
		"command/resultdata",
		{
			"method": "post",
			"parameters": "a=b&c=d&e=f",
			onSuccess: function(request) {
				// 成功時の処理を記述
				 alert('成功しました'+ request.responseText);
			},
			onComplete: function(request) {
				// 完了時の処理を記述
				 alert('読み込みが完了しました');
			},
			onFailure: function(request) {
				alert('読み込みに失敗しました');
			}
//			onException: function (request) {
//				何が悪いのか、必ずExceptionが発生…。requestが空っぽなので原因も分かりません。
//				alert('読み込み中にエラーが発生しました');
//			}
		}
	);
    }
}

↑は単にURLにアクセスしているだけ。
これでhtml内でid="result"の部分を書き換えようとしてます。
リクエストでもいいのかなあ。まだ試してない。

コメントアウトしている例外処理部分は成功しても、失敗してもエラー!といわれる…。
でも、コメントアウトしても、try〜catchには引っかからない。

  • controller
def resultdata
 @resultinfo = Hash::new
 @resultinfo[:hello] = "こんにちは!"
 render :partial => 'result',:object => @resultinfo , :as => :info
end
  • 部分テンプレート
<div id="result">
<h><%=info[:hello] %><
</div>

コントローラ→部分テンプレート部分はまだうまくできてないので保留…

ajax版できたよー

前回→railsサーバアプリ⇔ブラウザの同期 - スキマハコからの続き。
TODOのうち、以下のものを消化!

  • jqueryでの自動更新
  • リモート・フォームの送信の方法
  • application.rb
   # JavaScript files you want as :defaults (application.js is always included).
   # config.action_view.javascript_expansions[:defaults] = %w(jquery rails)
   # とりあえず、[jquery]→[rails.js]→[application.js]の順で読み込んでもらうー。
   # 既存にあるprototype.jsなどは消してません。
   config.action_view.javascript_expansions[:defaults] = %w(jquery.min rails)
  • application.js

sessionが維持できなくて苦労しました…。
参考にさせていただいたところ→AjaxのPOSTでsessionが取得できない - 屑プログラマの憂鬱

function method(page){
    // setIntervalの識別ID
    var intervalid = 0;
    $.ajax({
        url: $(page).attr('action'),
        type: 'POST',
        dataType: 'html',
        timeout: 1000,
        data : $(page).serialize(),
        beforeSend: function(xhr) {
            // sessionの引き継ぎ
            xhr.setRequestHeader('X-CSRF-Token', $('meta[name="csrf-token"]').attr('content'));
            $('#result').html('送信中...').fadeIn(200);
        },
        error: function(){
             $('#result').html('送信失敗!');
        },
        success: function(){
            // setIntervalの識別ID取得
            intervalid = setInterval(function() {
                $('#result').load("control/resultdata");
            }, 1000);
            // Intervalの終了処理タイムアウト設定
      // コントローラのresultdataよりも長めにとっとく。
            setTimeout(function(){
                clearInterval(intervalid);
            },30000);
        }
    });
    return false;
}
  • view
<% form_for 'test_action',:html => {:onsubmit => "return method(this);"} do |f|%>
<%= f.text_area :body, 'cols' => 40, 'rows' => 5 %>
<div>
	<%= f.submit "送信", :name => "send" %>
	<%= tag :input,:type=>'reset',:value=> "クリア" %>
	<%= tag :input,:type=>'button',:value=> "終了", :onclick=>"window.open('about:blank','_top').close();" %>
</div>
<% end %>
</div>
<div id='result'>
</div>
  • controller
 def test_action
    # セッションに追加
    session[:flag] = "フラグが立った!"
    session[:time] = Time.now.utc.to_i
    p session
 end
  def resultdata
    # 直接アクセスの場合、404にリダイレクト
    return redirect_to '/404.html' unless request.xhr?
    p session

  # さあチェックだ!
    if session[:flag]!=nil

   # なにかしらの処理。ファイルチェックとか?
   if (処理結果) == true
        session[:result] = "OK!"
      else
        # タイムアウトチェック
        difftime = (Time.now.utc.to_i - session[:time].to_i)

        # タイムアウト(10秒)
        if difftime > 10
          session[:flag] = nil
          session[:time] = nil
          session[:result] = "タイムアウトです。" + difftime.to_s + ""
        else
          session[:result] = "経過秒" + difftime.to_s + ""
        end
      end
    end
    # html出力〜
    render :text=>session[:result]
  end

あ、自動読み込みの場所はroutes.rbの設定をしないとつながらないかも。

問題点

Ajaxてきな、頻度高すぎるとサーバには負荷がかかるー。

railsサーバアプリ⇔ブラウザの同期


Javaとか.Netとかばっかり触っていたので、Webアプリとかそんなん本当にわからんちんです…。

やりたいこと。

Ajax(javascript)を使って、連携したい。
とりあえず、よくあるポーリング形式を実装したい。

遷移は以下の通り。
[登録ボタンおす]
javascriptは動いていない)

[クライアントが定期的にPOST]
javascriptが動く。画面の情報が格納されるまで繰り返す)

[終了]

環境設定(インストール)

Rails3.1からはjqueryが標準になるらしいけれど、現状入っていない*1ので、プラグインをインストール。
(参考:http://journal.sooey.com/137

Ajaxを試す

参考にしたのはこちら。

Ajax を追加する

Ajax を使うことで、Web ページの一部分のみを更新することができます。ほとんどの作業を、Rails ライブラリーが行ってくれます。このアプリケーションに Ajax を追加するためには、下記の 5 つを行う必要があります。

  1. JavaScript を使うように Rails を構成する。
  2. 単純に HTML リンクを描画するのではなく JavaScriptAjax リクエストを送信するように、time リンクを変更する。
  3. 更新すべき HTML フラグメントを指定する。
  4. 更新された HTML のコンテンツのための場所を用意する
  5. コントローラー・メソッドと、場合によっては Ajax レスポンスを描画するビューを作成する。

境界を越える: Ajax on Rails

もちろん、上記記事はRails3.0ではなく、2での実装なのでその個所についてはRails3.0用に修正を行いました。

リスト 5. show ビューを、Ajax を使うように変更する

<%= javascript_include_tag :defaults %>
<h1>Ajax show</h1>
Click this link to show the current 
<%= link_to_remote "time", 
    :update => 'time_div', 
    :url => {:action => "time"} %>.<br/>
<div id='time_div'>
</div>

↑をrails3.0で実現する場合は、以下の二つを用意することになるらしい。

  • view(今までの)
  • js(新しく)

とりあえず、rails3仕様に変更。

link_to 表示リンク,パス,:remote => true

なので、

<%= javascript_include_tag :defaults %>
<h1>Ajax show</h1>
Click this link to show the current 
<%= link_to "time","time",:remote => true%>.<br/>
<div id='time_div'>
</div>

に置き換え可能。この段階で、結果に遷移する!
js(新しく)はまだ分からず。。。
うーん、updateを指定できなくなったので、jsファイルが必要のようなのですが…。いまいちわかってません…。
これは後から。

リスト 8. リモート・メソッドを周期的にコールする

<%= javascript_include_tag :defaults %>
<h1>Ajax show</h1>
<%= periodically_call_remote :update => 'time_div', 
                             :url => {:action => "time"},
                             :frequency => 1.0 %>
<div id='time_div'>
</div>

periodically_call_remoteが破棄になっており、置き換えが必要です。

Prototype.js

rails.jsの方なのかな?
jqueryでなくても実現できました。

<script type="text/javascript">
  $(document).ready(function() {
    setInterval(function() {
      $('#time_div').load("time");
    }, 2000);
  });
</script>

"time"にはurl、#time_divは表示で更新をかける場所ですね。

TODO
  • jqueryでの自動更新
  • link_toでの部分更新方法
  • リモート・フォームの送信の方法

うがー。

*1:RailsにはAjaxを利用するライブラリ・構成はできているので、jqueryがなくてもプロトタイプ.jsの利用が可能のようです。

DevKidがないとjsonのインストールがエラー!

railsvistaにインストールしようとしたらエラーが出ました。
前はインストーラをダウンロードしたのだけれど、ここはぜひ!コマンドラインで入れたい!!

エラーの内容。

C:\Users\chago>gem install rails --include-dependencies
INFO:  `gem install -y` is now default and will be removed
INFO:  use --ignore-dependencies to install only the gems you list
Fetching: multi_json-1.0.4.gem (100%)
Fetching: activesupport-3.1.3.gem (100%)
Fetching: builder-3.0.0.gem (100%)
Fetching: i18n-0.6.0.gem (100%)
Fetching: activemodel-3.1.3.gem (100%)
Fetching: rack-1.3.5.gem (100%)
Fetching: rack-cache-1.1.gem (100%)
Fetching: rack-test-0.6.1.gem (100%)
Fetching: rack-mount-0.8.3.gem (100%)
Fetching: hike-1.2.1.gem (100%)
Fetching: tilt-1.3.3.gem (100%)
Fetching: sprockets-2.0.3.gem (100%)
Fetching: erubis-2.7.0.gem (100%)
Fetching: actionpack-3.1.3.gem (100%)
Fetching: arel-2.2.1.gem (100%)
Fetching: tzinfo-0.3.31.gem (100%)
Fetching: activerecord-3.1.3.gem (100%)
Fetching: activeresource-3.1.3.gem (100%)
Fetching: mime-types-1.17.2.gem (100%)
Fetching: polyglot-0.3.3.gem (100%)
Fetching: treetop-1.4.10.gem (100%)
Fetching: mail-2.3.0.gem (100%)
Fetching: actionmailer-3.1.3.gem (100%)
Fetching: rake-0.9.2.2.gem (100%)
Fetching: thor-0.14.6.gem (100%)
Fetching: rack-ssl-1.3.2.gem (100%)
Fetching: json-1.6.3.gem (100%)
ERROR:  Error installing rails:
        The 'json' native gem requires installed build tools.

Please update your PATH to include build tools or download the DevKit
from 'http://rubyinstaller.org/downloads' and follow the instructions
at 'http://github.com/oneclick/rubyinstaller/wiki/Development-Kit'

Please update your PATH to include build tools or download the DevKit
from 'http://rubyinstaller.org/downloads’ and follow the instructions
at 'http://github.com/oneclick/rubyinstaller/wiki/Development-Kit

てなメッセージを吐いてくれた。。。

DevKitなるものが無いと、json-1.6.1.gemがコンパイルできないようだ。

メッセージに従い
DevKitをダウンロードし、ダブルクリックすると、解凍先を聞いてくるので、C:\DevKit と指定する。
参考:Windows 7にRails 3.1.1をインストール - Route162

まさに同じ状況!
とりあえずダウンロード。

ほとんど参考のサイトさんのままで最後まで行けました!
一応記録。

C:\Users\chago\Desktop\新しいフォルダ>gem install rails --include-dependencie
s --platform mswin32
INFO:  `gem install -y` is now default and will be removed
INFO:  use --ignore-dependencies to install only the gems you list
Temporarily enhancing PATH to include DevKit...
Building native extensions.  This could take a while...
Fetching: rdoc-3.11.gem (100%)
Depending on your version of ruby, you may need to install ruby rdoc/ri data:

<= 1.8.6 : unsupported
 = 1.8.7 : gem install rdoc-data; rdoc-data --install
 = 1.9.1 : gem install rdoc-data; rdoc-data --install
>= 1.9.2 : nothing to do! Yay!
Fetching: railties-3.1.3.gem (100%)
Fetching: bundler-1.0.21.gem (100%)
Fetching: rails-3.1.3.gem (100%)
Successfully installed json-1.6.3
Successfully installed rdoc-3.11
Successfully installed railties-3.1.3
Successfully installed bundler-1.0.21
Successfully installed rails-3.1.3
5 gems installed
Installing ri documentation for json-1.6.3...
Installing ri documentation for rdoc-3.11...
Installing ri documentation for railties-3.1.3...
Installing ri documentation for bundler-1.0.21...
Installing ri documentation for rails-3.1.3...
Installing RDoc documentation for json-1.6.3...
Installing RDoc documentation for rdoc-3.11...
Installing RDoc documentation for railties-3.1.3...
Installing RDoc documentation for bundler-1.0.21...
Installing RDoc documentation for rails-3.1.3...