excelで住所を元に分類する
VBAも関数もあまり分からないので、以下でごり押し。
・B2に住所が書いてあるとする。
・countifでマッチングして、結果をifで条件分岐するだけ。。
・分類したい住所の数だけifが増えていく。。。
=IF(COUNTIF(B2, "埼玉*"), "埼玉", IF(COUNTIF(B2, "北海道*"), "北海道", IF(COUNTIF(B2, "東京*"), "東京", IF(COUNTIF(B2, "静岡*"), "静岡", "分類無し"))))
以下はメモ用。
sheet1がデータシートとする。
=IF(COUNTIF(Sheet1!C:C, C3), INDEX(Sheet1!A:A, MATCH(C3, Sheet1!C:C, 0)), "")
prototype.jsのサンプル
ちょっとprototype.jsを使う機会があったので、忘れないように使い方を書いておこう。
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml"> <head> <meta http-equiv="content-type" content="text/html;charset=utf-8"> <title>Sample</title> <script type="text/javascript" src="/javascript/prototype.js"></script> <script type="text/javascript"> var numCount = 0; var isRequestSend = false; function request() { if(!isRequestSend) { isRequestSend = true; var data = {q: 'パラメータ', a: numCount}; var req = new Ajax.Request( 'test.php', { method : 'get', parameters: $H(data).toQueryString(), onSuccess : onSuccessHandler, onFailure : onFailureHandler } ); } } function onSuccessHandler(res) { var data = eval( "(" + res.responseText+ ")" ); insertResult(data); numCount++; isRequestSend = false; } function onFailureHandler() { isRequestSend = false; } function insertResult(data){ for(var i=0; i<data.length; i++) { var node = document.createElement("a"); node.href = 'index.html'; var d = data[i]; node.innerHTML = "param1:"+ d['param1']+"param2:"+ d['param2']; var parent = $("result"); parent.insertBefore(node, $("point")); } } </script> </head> <body> <form> <a onclick="request();">test</a> </form> <div id="result"> <div>element1</div> <div id="point">element2</div> </div> </body> </html>
「Rubyベストプラクティス」を読む4
4章はファイルやテキスト処理、正規表現をあつかっています。
目次:4章 テキスト処理とファイル管理
4.1 状態トラッキングによる行指向のファイル処理
テキスト処理について、パーサーをつくる一つの方法が紹介されています。
# 本に載っているパーサーのコードを一部簡単にして書く def parse(file_name) # 状態を保持する配列 section = [] File.foreach(file_name) do |line| # 状態を変更する処理 # 状態はスタックで管理する case line when /^Start(\w+)/ section.push $1 next when /^End(\w+)/ section.pop next end # 現在の状態で行う処理を決める case section when ["Font", "Metrics"] parse_char(line) when ["Kern"] parse_kern(line) when ["Metric"] next # 処理しなくてもよいときは、nextで飛ばす else parse_generic(line) # その他一般の処理 end end end
4.2 正規表現
アンカーや量指定子の使い方が解説されている。
4.3 ファイルを扱う
テンポラリファイルを使う必要があるときは、自作するよりtempfileライブラリを使う。
require 'tempfile' temp = Tempfile.new('foo.txt') temp << some_data # 読み込むときは、rewindで巻き戻す temp.rewind temp.each do |line| # 何かする end temp.close # テンポラリファイルをすぐに削除したいときは、Tempfile#close! を使う。 # temp.close! # テンポラリディレクトリを指定することもできる a = Tempfile.new("foo.txt", "path/to/tmpdir")
File.foreachはEnumeratorを返すので、テキスト処理にEnumerableのメソッドが使える
sum = 0 File.foreach("data.txt"){|line| sum += line[/total: (\d+)/, 1].to_f} # Enumeratorを使った処理 enum = File.foreach("data.txt") sum = enum.inject(0){|s, r| s + r[/total: (\d+)/, 1].to_f}
ファイル処理をしていて、現在の行数を知りたいときは、File#linenoを使う
keys = [] values = [] File.open("foo.txt") do |file| file.each do |line| (file.lineno.odd? ? keys : values) << line.chomp end end Hash[*keys.zip(values).flatten]
ファイルに修正を施して保存する場合、"r+"でファイルを開いて処理するよりも、テンポラリファイルに処理結果を書いておいて、最後にリネームするやり方のほうが簡単。
require "tempfile" require "fileutils" file_name = "data.txt" temp = Tempfile.new("working") File.foreach(file_name) do |line| # 何かする temp << result end temp.close # 安全のため、ファイルをバックアップしておく FileUtils.cp(file_name, "#{file_name}.bak") FileUtils.mv(temp.path, file_name)
「Rubyベストプラクティス」を読む3
3章の話は、2章と似たような優れたインターフェイスの作り方やRubyのリフレクションが紹介されています。
3章目次
BlankSlate:ステロイドで強化されたBasicObject
BlankSlateというライブラリの紹介。メソッドを公開、非公開する仕組みをもったクラス。
仕組みは、メソッドを非公開にするときは、Module#instance_methodで、UnboundMethodを取得しておいてから、undef_methodでメソッドを削除する。
メソッドを公開するときは、取得しておいたUnboundMethodをModule#define_methodに与えて、メソッドを定義する。
柔軟なインターフェイスを作る
instance_eval()をオプション化する
2章で紹介した、instance_evalを使ってselfを変えるAPIはカッコイイけど、selfが変わることが都合が悪い時がある。
class Document def self.generate(file, &block) d = Document.new d.instance_eval(&block) d.write(file) end def text(arg) # 何かする end end class Foo def bar "bar" end def use_document Document.generate("test.txt") do # selfがDocumentオブジェクトなので、下のFoo#bar呼び出しは使えない text "my document #{bar}" end end end
こういうときは、ブロックに与えられた引数の個数を調べて、instance_evalを使うか、自身のオブジェクトを引数として与えるか
選択するようなコードを書ける。
class Document def self.generate(file, &block) d = Document.new block.arity < 1 ? d.instance_eval(&block) : block.call(d) d.write(file) end end class Foo def use_document Document.generate("test.txt") do |d| d.text "my document #{bar}" end end end
method_missing()とsend()を使ってメッセージを扱う
method_missingでメソッド名を解析して、解析した文字列を、sendでメソッド呼び出しする例。
例えば、fill_and_strokeというメソッド呼び出しをmethod_missingでフックして、fillとstrokeのメソッドを呼び出すとか。
ActiveRecordのfind_by_*** とかと同じような仕組みの話だとおもう。
2つの目的を兼ねたアクセサ
メソッドに引数があれば、セッターとして動作して、引数がなければゲッターとして動作するメソッドの話。
これが必要になるのは、instance_evalを使ったAPIを提供しようとするとき、=の付くセッターでは、ローカル変数とみなされてしまうから。
Document.generate do # selfを指定しなければいけない self.font_size = 10 text "the font size is #{font_size}" end # セッター、ゲッターとして動作するメソッドを作る class Document def font_size(size=nil) return @font_size unless size @font_size = size end end Document.generate do # selfを指定しなくても書ける font_size(10) text "the font size is #{font_size}" end
オブジェクトごとの振る舞いを実装する
特異クラスを使って、オブジェクト固有のメソッドを作る話
user = User.new # 特異クラスの取得 singleton = class << user; self; end # メソッド定義 singleton.__send__(:define_method, :logged_in?){ true }
既存のコードを拡張、変更する
新しい機能を追加する
オープンクラスなので、メソッドを追加で定義できるという話。
エイリアス経由で変更する
メソッドに機能を追加したいとき、Module#alias_methodを使ってメソッドの名前を変えて、追加の機能を実装した同名メソッドを作れる。
オブジェクトごとの変更
オブジェクトをextendして追加の機能を持たせることができる。クラス単位の変更となるModule#alias_methodと違って、こちらの方法はオブジェクトごとの変更になる。
クラスとモジュールをプログラムで作る
Class#newで匿名クラスを作れる。Class#newのブロック内でdefすれば、匿名クラスのインスタンスメソッドを作成できる。
def Mystery(secret) if secret == "chunky" Class.new do def message "You" end end else Class.new do def message "Don't" end end end end class Win < Mystery("chunky") def who_am_i "I am Win" end end class EpicFail < Mystery("smooth ham") def who_am_i "I am teh fail" end end
フックとコールバックを登録する
新しく追加された機能を検出する
メソッド定義をmethod_addedでフックできる。
継承を補足する
継承はinheritedでフック出来る。
Mix-inを補足する
includeはincludedでフック出来る。本でも紹介されているけど、以下のようなincludedの使い方を結構見かける気がする。
module MyModule module ClassMethods def class_method # クラスオブジェクト用のメソッド end end def foo # インスタンス用のメソッド end def self.included(base) base.extend(ClassMethods) end end class Foo include MyModule # includedのおかげで、下のようにextendを書く必要はない # extend MyModule::ClassMethods end
まとめ
章の最後では、この章で紹介されたテクニックを使ったNaiveCampingRoutesという面白いコードが書いてある。
「Rubyベストプラクティス」を読む2
2章はメソッドの作り方に関する章。
良いメソッドを書くための、引数やブロックの使い方が書かれています。
色々なメソッドの引数処理
# 標準的な引数 def distance(x1, y1, x2, y2) Math.hypot(x2-x1, y2-y1) end # オプションパラメータのある引数 def load_file(name, mode="rb") File.open(name, mode) end # 疑似キーワード引数 # 下のように呼べる # story(animal: "Tiger", person: "Yankee Doodle") def story(options) # デフォルト値を持たせて、mergeするやり方もある。 options = {person: "person", animal: "animal"}.merge(options) "#{options[:person]} went to town, riding on a #{option[:animal]}}" end # 引数を配列として使う def distance2(*points) distance(*points.flatten) end
ブロックを使う
イテレートとか、前処理や後処理があるメソッドはブロックを使うようにすると綺麗になる。
イテレートのメソッドを定義するときは、Enumerableが使えるか検討する。
コールバックもブロックを使ってできる。&blockでブロックを受け取り、あとで呼び出す。
また、以下のようにinstance_evalを使って、APIをきれいにできる。
# 以下のようなコードで使用するオブジェクトがあるとする # server = Server.new # server.handle(/hello/){"hello"} # server.handle(/bye/){"bye"} # server.run # # instance_evalを使って、以下のように呼び出せるようにする # Server.run do # handle(/hello/){"hello"} # handle(/bye/){"bye"} # end class Server def self.run(port=3333, &block) server = Server.new(port) server.instance_eval(&block) server.run end end
「Rubyベストプラクティス」を読む1
数か月前に、一度「Rubyベストプラクティス」を読んでいたけれど、良い内容だったので
復習のために、もう一度読みなおしてみる。大事そうなところを日記に書いておこう。
まずは1章から、テストの話。
メソッドを分割する
本に載っている例。以下のようなコードをテストするとする。
class Questioner # questionの文字列を出力して、標準入力を待つ。 # 入力の内容によって、以下のような動きをする # y Y Yes YeS YES yes など => trueを返す。 # n N No nO など => falseを返す。 # それ以外 => もう一度 askを呼ぶ。 def ask(question) puts question response = gets.chomp case(response) when /^y(es)?$/i true when /^no?$/i false else puts "I don't understand." ask question end end end
まずはテストしやすいように、コードを分割する。この場合、getsをほかの部分と分離させる。
class Questioner def ask(question) puts question response = yes_or_no(gets.chomp) response.nil? ? ask(question) : response end def yes_or_no(response) case(response) when /^y(es)?$/i true when /^no?$/i false end end end
これで、yes_or_noメソッドは簡単にテストできる。例えば、minitestを使えば
def setup @questioner = Questioner.new end def test_yes %w(y Y Yes YES yes).each do |yes| assert @questioner.yes_or_no(yes), "#{yes.inspect} expected to parse as true" end end
とできる。askメソッド以外はテスト出来るようになる。
スタブを使う
次に、askメソッドを呼び出しているようなメソッドをテストする場合。
class Questioner def inquire_about_happiness ask("Are you happy?") ? "Good" : "That's Too Bad" end end
askは内部でgetsを使っているので、テストしにくい。このようなときは、特異メソッド定義を使って、askをスタブで置き換える。
def setup @questioner = Questioner.new end def test_yes def @questioner.ask(question); true; end assert_equal "Good", @questioner.inquire_about_happiness end def test_no def @questioner.ask(question); false; end assert_equal "That's Too Bad", @questioner.inquire_about_happiness end
モックを使う
putsやgetsを使っているaskメソッドをテストするには、IOオブジェクトのように振舞うオブジェクトを使えばいい。
まずはputsやgetsを、IOオブジェクトへのメソッド呼び出しに書き直す。
class Questioner def initialize(in=STDIN, out=STDOUT) @input, @output = in, out end def ask(question) @output.puts question response = yes_or_no(@input.gets.chomp) response.nil? ? ask(question) : response end end
テストではIOオブジェクトをStringIOなどにすれば、askメソッドもテストできる。
def setup @in = StringIO.new @out = StringIO.new @questioner = Questioner.new(@in, @out) @question = "Are you happy?" end def test_ask @in << "yes" @in.rewind assert @questioner.ask(@question), "Expected yes to by true"; assert_equal "#{@question}\n", @output.string end
ActionScriptとJavaScriptの連携(ExternalInterface)
ActionScriptからJavaScriptを呼んだり、またはその逆をやりたいときはExternalInterfaceを使えばいいんだけど、今までやったことなくて、少しハマったのでメモしておく。
ActionScriptからJavaScriptの関数を呼ぶ。
ExternalInterface.callを使う。
Security.allowDomain(ExternalInterface.call("function() { return location.hostname }")); // javascriptのalertを呼ぶ。 ExternalInterface.call("alert('hello')");
JavaScriptからActionScriptの関数を呼ぶ。
ExternalInterface.addCallbackで、JavaScriptから呼び出したい関数を登録しておく。
JavaScript側で、埋め込まれたSWFObjectを取得して、その取得したオブジェクトに対して、addCallbackで登録しておいたメソッドを呼び出す。
// ActionScript側 // 第1引数が、JavaScript側で呼び出すときの関数名になる。 // 第2引数が、登録する関数。 第1引数と第2引数の関数名は同じでなくてもよい。 ExternalInterface.addCallback("doSomething", doSomething); public function doSomething():void { // 何かする。 }
// JavaScript側。swfobject.jsを使って埋め込んだとする。 var flashvars = {}; var params = { menu: "false", scale: "noScale", allowFullscreen: "true", allowScriptAccess: "always", bgcolor: "#FFFFFF" }; var attributes = { id:"AppTest", name:"AppTest" }; swfobject.embedSWF("AppTest.swf", "altContent", "100%", "100%", "9.0.0", "expressInstall.swf", flashvars, params, attributes); // この関数を呼べば、上で登録したActionScriptの関数が呼べる。 function callActionScript() { var swf = document.getElementById("AppTest"); // attributesのidを指定する。 swf.doSomething(); }