pikをインストールしたよー
※rubyインストールツールとしてはあんまり使えない。あくまでバージョン切替ツールくらいの認識でよい。
Gitからダウンロードした*.msiを利用した。
参考
ほとんど参考先の通りなので、先に出しておきます…。
pik を使って Windows に ruby をインストール - miauの避難所
Windows7にRubyInstaller+Pikで複数バージョンのRuby環境を整える - ひろうぃんの雑記
環境
rubyはインストールしていなくてもいいけれど、空っぽの場合は.pik\config.ymlファイルを編集しないといけない。
順番
インストールができていたら、次の通りに動くはず。
$C:\Users\chago>pik list => 193: ruby 1.9.3p545 (2014-02-24) i386-mingw32 #プロキシ経由の環境なので、環境変数に一時的にあてとく $C:\Users\chago>set http_proxy=XXX.XXX.XXX.XXX:80 #リモートからダウンロード/インストールできるrubyのリスト $C:\Users\chago>pik list -r The --remote parameter is deprecated and will be removed in a future release. use 'pik list known' instead. # MRI Ruby [ruby-]1.8.7-p302 [ruby-]1.8.7[-p330] [ruby-]1.9.1[-p430] [ruby-]1.9.2-p0 [ruby-]1.9.2[-p136] # IronRuby ironruby-1.0.0 ironruby-1.1.0 ironruby[-1.1.1] # JRuby jruby[-1.5.6] jruby-1.6.0.RC1
NetBeansを入れたら怒られたよー
versionは既に7以降をつかっていたんだけど、どうしても6.9.1を入れる必要があって。
新しいマシンにNetBeans6.9.1をインストール後、実行したら次の警告メッセージが。
Cannot locate java installation in specified jdkhome:
C:\Program Files\Java\jdk1.6.0_24
Do you want to try to use default version?※意訳:デフォルトだとNetBeansのJDKバージョンが1.6.0_24だけど見つかんないよ!YouこれでOKなの!?
(OK押しても結局起動は失敗する)
といわれる。
どうやら、インストール時にJDK1.8.Xを指定したのが悪かったみたい。
設定ファイルを書き換えて自マシン内の環境に合わせてあげる。
修正後に保存し、再度実行したらするっと起動します。
RubyをWindowsで複数バージョン管理するー
Rubyは1.8.Xや1.9.X、2.0.Xとそれぞれバージョンをもっておきたいもの。
Linuxではrbenvさんが一般的。
rubyバージョン管理ツール rbenv インストール手順 - Nerdstacks.net
Windowsではpikさんが一般的っぽい。
Windowsに複数バージョンのRubyをインストールする | GENDOSU@NET
BeginEditとEndEditの働き
忘れそうなのでメモしておく。
バインドしていると、BeginEditは呼ばなくても開始している。
働きとして2つ。
- RowStateの更新
- Row値についてのバージョン管理切替え
メンバー名 説明 Original この行には元の値が格納されています。 Current この行には現在の値が格納されています。 Proposed この行には提示された値が格納されています。 Default DataRowState の既定バージョン。 DataRowState の値が Added、Modified、または Deleted の場合、既定バージョンは Current です。 DataRowState の値が Detached の場合、既定バージョンは Proposed です。
EndEditを呼ばない限り、編集中なのでバインドしているコントロールの値はProposedに格納されたままでCurrent(現在の値)にはならない。
AcceptChanges メソッドを呼び出すと、Original 値が Current 値と同じになってしまうので、変更を比較したい時には利用しない。
あと、RejectChangesメソッドは保留中のProposedを消してしまうのはCancelEditと同じ動きっぽい。
VB.NETからExcelファイルのデータを読み込むには
やりたいこと。
★一覧表の領域と、その他情報領域が存在する。役割ごとに名前付きセルとして定義してあるので、そこから情報を取得する。
※名前付きセルはファイルに一意に存在するよう定義する。
方法案
- マクロで読込できる形式で吐き出し(CSVとか)、そのファイルを分析して、取得する。
- VB.NETからExcelに対してDB接続し、情報を取得する
- COM相互運用を利用し、VB.NETからExcelオブジェクトに対して情報を取得する
- VSTOを使う
メリット・デメリット
1.一番原始的な気がする。
メリット: 確実。
デメリット:ファイル監視が絡む。
2.インポートと言えばこれ。
メリット: 無駄なく取れそう(したことない)
デメリット:帳票形式のデータインポートには向いていない。
4はクライアントにもVSTOをインストールする必要があるようなので、今回は見送り。
3については経験がなかったので、実験してみた。
やってみる
初めに書いたソース
' ファイルパスはOpenFileDialogを利用し、確実に存在する前提。 Private Sub Read(ByVal ustrFilePath As String) ' Excelを操作クラス Dim excelApp As Excel.Application = Nothing Dim wkbk As Excel.Workbook = Nothing Dim sheets As Excel.Sheets = Nothing Dim wksheet As Excel.Worksheet = Nothing ' データ取得クラス Dim rangeDataList As Excel.Range = Nothing Dim rangeYear As Excel.Range = Nothing Dim nmsNames As Excel.Names = Nothing ' 結果格納 Dim data(,) As Object Dim strYear As String Try ' Excelアプリケーションの開始 excelApp = New Excel.Application ' ファイルオープン wkbk = excelApp.Workbooks.Open(ustrFilePath) sheets = wkbk.Worksheets wksheet = sheets(1) ' 取得 nmsNames = wkbk.Names For i = 0 To nmsNames.Count - 1 ' 一致する名前定義クラスから、参照するRangeを取得 If nmsNames(i).Name = "DataList" Then rangeDataList = nmName.RefersToRange ElseIf nmsNames(i).Name = "Year" Then rangeYear = nmName.RefersToRange End If Next If rangeDataList Is Nothing OrElse rangeYear Is Nothing Then exit sub End If ' 格納 data = DirectCast(rangeDataList.Value, Object(,)) strYear = rangeYear.Value Catch Throw Finally ' 解放 nmsNames = Nothing rangeYear = Nothing rangeDataList = Nothing wksheet = Nothing sheets = Nothing wkbk = Nothing wkbks = Nothing ' Close Excel. excelApp.Quit() excelApp = Nothing End Try End Sub
わあ!ひどいありさまだ!
このソースだと、このメソッドを呼ぶたびにExcelプロセスが残っていき、元プロセスが終了しない限り(または終了しても残るかも)、見た目的にデーモンなプロセスがどんどん増えていきます。
上手く解放が行われていないため、Excel終了を読んでもプロセスが死なないのですね。
修正しよう
- 解放を適切に行おう。
COM相互運用というのは.NET ⇔ ランタイム呼び出し可能ラッパー (RCW: Runtime Callable Wrapper) ⇔ COMの関係で動きます。
RCWが適切に解放されないと、Excelプロセスは終了出来ないのです。
解放には ReleaseComObjectメソッド、あるいはFinalReleaseComObjectを利用します。
解放の記述を修正です。
' 解放を修正 Finally ' 解放(全ての解放を行うため、FinalReleaseComObjectを利用します) If Not nmsNames Is Nothing Then System.Runtime.InteropServices.Marshal.FinalReleaseComObject(nmsNames) nmsNames = Nothing End If If Not rangeYear Is Nothing Then System.Runtime.InteropServices.Marshal.FinalReleaseComObject(rangeYear) rangeYear = Nothing End If If Not rangeDataList Is Nothing Then System.Runtime.InteropServices.Marshal.FinalReleaseComObject(rangeDataList) rangeDataList = Nothing End If System.Runtime.InteropServices.Marshal.FinalReleaseComObject(wksheet) System.Runtime.InteropServices.Marshal.FinalReleaseComObject(sheets) System.Runtime.InteropServices.Marshal.FinalReleaseComObject(wkbk) wksheet = Nothing sheets = Nothing wkbk = Nothing ' Close Excel. excelApp.Quit() System.Runtime.InteropServices.Marshal.FinalReleaseComObject(excelApp) excelApp = Nothing End Try
Nothingの代入は不要かもしれません。むだかなーと思いつつもやってます。
解放の順番も重要です。
COMは次のような階層構造になっています。
Application
Workbooks
Workbook
Worksheets
Worksheet
Range
ですので、子供から先に解放すべきです。
ここまで来ても、まだ解放されません…。
- 暗黙的にキャストされている箇所はRCWが生まれている。
なんと恐ろしいことでしょう。
次のような箇所に該当します。
' ファイルオープン wkbk = excelApp.Workbooks.Open(ustrFilePath) ' ← Workbooksを暗黙的に変換している! sheets = wkbk.Worksheets wksheet = sheets(1)
このように.が2つ以上ある場合は暗黙的にキャストが働いていると考えて構いません。
こうして発生したRCWの参照は解放されず、どうしようもなくなります。
全て、一度変数で参照させて最後に必ず解放するようにしましょう。
' Excelを操作クラス Dim excelApp As Excel.Application = Nothing Dim wkbks As Excel.Workbooks = Nothing Dim wkbk As Excel.Workbook = Nothing Dim sheets As Excel.Sheets = Nothing Dim wksheet As Excel.Worksheet = Nothing ' Excelアプリケーションの開始 excelApp = New Excel.Application wkbks = excelApp.Workbooks ' ← 暗黙的変換を回避 ' ファイルオープン wkbk = wkbks.Open(ustrFilePath) sheets = wkbk.Worksheets wksheet = sheets(1)
- 繰り返しの中で代入した場合は毎回解放する
ループ文で回している場合は、利用後に毎回解放しましょう。
※なんか怖いので。
' 取得 nmsNames = wkbk.Names For i = 0 To nmsNames.Count - 1 nmName = nmsNames(i) ' 一致する名前定義クラスから、参照するRangeを取得 If nmName.Name = "DataList" Then rangeDataList = nmName.RefersToRange ElseIf nmName.Name = "Year" Then rangeYear = nmName.RefersToRange End If ' 解放(参照が切り替わるので、毎回解放しないとゴミとして残るのでは…) System.Runtime.InteropServices.Marshal.ReleaseComObject(nmName) nmName = Nothing Next
- DirectCastはつかっちゃだめ
キャストが走るので、解放できないRCWが出来てしまうのです。
ふつーに代入しちゃいましょう。
data = rangeDataList.Value
まとめ
- RCWは必ず解放する
- 暗黙的なキャストはしないで、必ず変数に格納する
- 解放するときはCOMの階層構造を意識した順番で行う。
参考:
http://msdn.microsoft.com/ja-jp/library/vstudio/ee317478%28v=vs.100%29.aspx
http://eikunti.blog.fc2.com/blog-entry-19.html
http://shinichiaoyagi.blog25.fc2.com/blog-entry-180.html
http://support.microsoft.com/kb/302094
http://jeanne.wankuma.com/tips/vb.net/excel/
http://igeta.cocolog-nifty.com/blog/2007/07/rcw.html
VirtualBox+GestOS(CentOS)でローカル開発環境を作るよー
前回は外部のネットワークにつなげるように設定したのだけれど、あくまでローカルに開発するよっていう時。
- ホストOSと通信出来る
- Virtual Host Only アダプタ
- 外部ネットワークから受信(yumなどが出来るように)のみをしたい
- NAT
というわけで、それぞれのネットワークアダプタをGestOSの設定より指定する。(起動前)
プロキシで外につなぐ
NATは「DHCP による IPアドレスの自動取得」でアドレスを設定する。このため、ゲートウェイとDNSサーバの設定が必須になるみたい。
(DHCP による IPアドレスの自動取得設定は有効の場合)
プロキシを利用している場合はhttpサーバにプロキシを設定する必要がある。
Proxy
以下の二つのファイルを作成。
$ cat /etc/profile.d/proxy.csh setenv http_proxy http://プロキシサーバアドレス:ポート番号/ setenv ftp_proxy http://プロキシサーバアドレス:ポート番号/ setenv HTTP_PROXY http://プロキシサーバアドレス:ポート番号/ setenv FTP_PROXY http://プロキシサーバアドレス:ポート番号/
$ cat /etc/profile.d/proxy.sh #!/bin/sh export http_proxy=http://プロキシサーバアドレス:ポート番号/ export ftp_proxy=http://プロキシサーバアドレス:ポート番号/ export HTTP_PROXY=http://プロキシサーバアドレス:ポート番号/ export FTP_PROXY=http://プロキシサーバアドレス:ポート番号/
HerokuでWebサービスを公開するまでの記録をするよー
環境もろもろの設定
基本的な開発環境の設定はこちらを参考にしました。
Heroku(ヘロク)で,Ruby on Railsアプリを簡単に公開する方法の入門 (無料のRuby向けPaaS環境の使い方) - 主に言語とシステム開発に関して
IDEはNetBeans7を利用します。
設定方法の参考はこちら:
NetBeans 7.1にRuby on Railsプラグインをインストールする手順 - Rails 雑感 - Ruby on Rails with OIAX
ということでいまはこんな感じ。
# Rubyのバージョン $ruby --version ruby 1.9.3p125 (2012-02-16) [i386-mingw32] # Gemのバージョン $gem --version 1.8.16 # Railsインストール $gem i rails # Gemインストール状況 $gem list *** LOCAL GEMS *** addressable (2.2.8) bigdecimal (1.1.0) bundler (1.1.4) excon (0.14.3) heroku (2.28.10) heroku-api (0.2.7) io-console (0.3) json (1.5.4) launchy (2.1.0) mime-types (1.19) minitest (2.5.1) netrc (0.7.5) rake (0.9.2.2) rdoc (3.9.4) rest-client (1.6.7) rubyzip (0.9.9) # ----- rails3.2で以下がインストール actionmailer (3.2.6) actionpack (3.2.6) activemodel (3.2.6) activerecord (3.2.6) activeresource (3.2.6) activesupport (3.2.6) arel (3.0.2) builder (3.0.0) erubis (2.7.0) hike (1.2.1) i18n (0.6.0) journey (1.0.4) mail (2.4.4) multi_json (1.3.6) polyglot (0.3.3) rack (1.4.1) rack-cache (1.2) rack-ssl (1.3.2) rack-test (0.6.1) rails (3.2.6) railties (3.2.6) sprockets (2.1.3) thor (0.15.4) tilt (1.3.3) treetop (1.4.10) tzinfo (0.3.33) # Gitの場所。現在64bitOSで開発中。でもなんかここに設定される…。 $where git C:\Program Files (x86)\Git\cmd\git.exe
Railsのプロジェクトを作るよ
ここはNetBeansでプロジェクトを作るための備忘録になる。
Rubyプラットフォームはマシンにインストールしているバージョンであればいずれも選択可能。
コマンドラインで入力しても可
d:\>rails new meigo
jsonのエラーが出る場合
前も出た気がするんだけど・・・。
railsアプリケーションを作ったら、こんな風に表示される。
Gem::InstallError: 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' An error occured while installing json (1.7.3), and Bundler cannot continue. Make sure that `gem install json -v '1.7.3'` succeeds before bundling.
これにはこちらを参考にしました:
[仕事]WindowsでのRails3環境構築: サウスポーなSEの独り言
どうやらビルドするためのライブラリなどが足りない様子。
devkitをダウンロード:Download Archives
展開するときは専用のディレクトリを用意したほうがいいかな。
d:\devkit>ruby dk.rb init [INFO] found RubyInstaller v1.9.3 at C:/Ruby193 Initialization complete! Please review and modify the auto-generated 'config.yml' file to ensure it contains the root directories to all of the installed Rubies you want enhanced by the DevKit. d:\devkit>ruby dk.rb install [INFO] Updating convenience notice gem override for 'C:/Ruby193' [INFO] Installing 'C:/Ruby193/lib/ruby/site_ruby/devkit.rb'
この状態で、もう一度rails new アプリをして、エラーが出なければ終了。
なにを作る?
ここまできてから何を作るかって言うのもちょっとおばかさんなのだけれど、今回はtwitterのbotを作る。
参考サイト:Herokuを使って1日1回名言をツイートするTwitter Botの作り方 - アインシュタインの電話番号☎
twitterのための設定
botのための準備。
twitterサービス用の設定
こちらを参考:8分21秒で分かるRubyとOAuthによるTwitterAPIの使い方(動画) - 昼メシ物語
現在(2012/7)だと記述形式はちがうけど、大体これにのっとって設定したよ。
twitter-oauthの設定
こちらを参考:Herokuを使って1日1回名言をツイートするTwitter Botの作り方 - アインシュタインの電話番号☎
すごく丁寧でわかりやすい!
この手順にほぼ従い、やっていったんだけど…。
herokuのログを見る
$heroku logs 2012-07-07T16:02:27+00:00 app[web.1]: /app/config.ru:2:in `require': no such file to load -- app.rb (LoadError) 2012-07-07T16:02:27+00:00 app[web.1]: from /app/config.ru:2:in `block in <main>' 2012-07-07T16:02:27+00:00 app[web.1]: from /app/vendor/bundle/ruby/1.9.1/gems/rack-1.4.1/lib/rack/builder.rb:51:in `instance_eval' 2012-07-07T16:02:27+00:00 app[web.1]: from /app/vendor/bundle/ruby/1.9.1/gems/rack-1.4.1/lib/rack/builder.rb:51:in `initialize' 2012-07-07T16:02:27+00:00 app[web.1]: from /app/config.ru:1:in `<main>' 2012-07-07T16:02:27+00:00 app[web.1]: from /app/config.ru:1:in `new' 2012-07-07T16:02:27+00:00 app[web.1]: from /app/vendor/bundle/ruby/1.9.1/gems/rack-1.4.1/lib/rack/builder.rb:40:in `eval' 2012-07-07T16:02:27+00:00 app[web.1]: from /app/vendor/bundle/ruby/1.9.1/gems/rack-1.4.1/lib/rack/builder.rb:40:in `parse_file' 2012-07-07T16:02:27+00:00 app[web.1]: from /app/vendor/bundle/ruby/1.9.1/gems/rack-1.4.1/lib/rack/server.rb:200:in `app' 2012-07-07T16:02:27+00:00 app[web.1]: from /app/vendor/bundle/ruby/1.9.1/gems/rack-1.4.1/lib/rack/server.rb:301:in `wrapped_app' 2012-07-07T16:02:27+00:00 app[web.1]: from /app/vendor/bundle/ruby/1.9.1/gems/rack-1.4.1/lib/rack/server.rb:252:in `start' 2012-07-07T16:02:27+00:00 app[web.1]: from /app/vendor/bundle/ruby/1.9.1/gems/rack-1.4.1/lib/rack/server.rb:137:in `start' 2012-07-07T16:02:27+00:00 app[web.1]: from /app/vendor/bundle/ruby/1.9.1/gems/rack-1.4.1/bin/rackup:4:in `<top (required)>' 2012-07-07T16:02:27+00:00 app[web.1]: from /app/vendor/bundle/ruby/1.9.1/bin/rackup:19:in `load' 2012-07-07T16:02:27+00:00 app[web.1]: from /app/vendor/bundle/ruby/1.9.1/bin/rackup:19:in `<main>' 2012-07-07T16:02:29+00:00 heroku[web.1]: Process exited with status 1 2012-07-07T16:02:29+00:00 heroku[web.1]: State changed from starting to crashed
えーと設定が足りないのかしら・・・。
rubyのバージョンにあった記述になっているか?
herokuのバージョンは1.9.x。RubyでTwitterのOAuth認証に必要なトークンを取得する - アインシュタインの電話番号☎のままでは稼動できないことに気づきました。
- ソースエンコーディングは明示的に!
マジックコメントというやつですね。
# encoding: utf-8
- requireで相対ソースファイルを読み込むときは"."をつける。
これは1.9.xからrequireの動作が変わったのが原因。
もともとは、requireはロードパスに基づいて、ライブラリを探すのですが、1.9からカレントディレクトリが除外されたので、見に行けなくなったのでした…。
解決方法として以下のとおり。
好みがあるかも。
# 明示的カレントを見るようにする。 require './app.rb' # 相対パスで見に行く用の記述にする require_relative 'app.rb' # ロードパスにカレントディレクトリを追加しちゃう $:.unshift File.dirname(__FILE__) require 'app.rb'
もー!私のうっかりさんめ…
とはいえ、Railsアプリとしてnewした場合はapp.rbには最初から$:.unshift File.dirname(__FILE__)みたいな記述があるので、本当は詰まらなかったところかも。