blah blah

ruby 기초 예 – multiple values return, Variable Arguments

수작업으로 해야할 일 생겨서 스크립트로 처리하고 간단히 메모했던 몇 건들을 블로그에 나눠서 옮겨 적어본다.

처음 건은 간만에 ruby 로 했던 …

*********************

서버 쪽 구성이 변경되면서 이 틈을 타고 데이타 재 인터페이스에 대한 요청이 몰려드네요. 수작업으로 건별 처리하다 짜증나서 간만에 루비 스크립트를 짜봤습니다.
수작업으로 하려면 잔손이 많이 가서 그렇지 작업 패턴은 단순해서 구현에는 그다지 특별한 내용은 없었습니다. 그래도 몇가지 기초적이지만 재미난 것들만 뽑아서 적어봅니다.

1. ruby는 복수의 값 리턴이 가능합니다. 이런 식이죠.

def getSql(msg_id)
case msg_id
when “M025”
sql = “select …. from goods”
module_name = “goods”
when “M001”
sql = “select …. from customer”
module_name = “customer”
end

return module_name, sql
end

module_name, sql = getSql(“M025”)

 

자바 등에서는 이런 경우에 array 나 collection 등을 쓰겠지만 루비에서는 이렇게 간편하게 …

2. 루비는 Variable Arguments(가변인수)를 쓸 수 있습니다.

def fetchIf(dbh, msg_id, *seg)
….
end

fetchIf(dbh, “MDM001”, “US000025”)
fetchIf(dbh, “MDM001”, “GOODS”, “TR01”)

 

위의 함수 선언부에 *seg 라고 한 부분 보이시죠? 이런 식으로 “*”을 붙여서 가변인수를 사용할 수 있답니다.
가변 인수로 지정된 인자들은 배열 형태로 처리되므로 쉽게 사용 가능하죠.

그런데 여기서 제가 꽤 헤메었습니다.

def fetchIf(dbh, msg_id, *seg)
module_name, sql = getSql(msg_id)
rs = dbh.prepare(sql)

if seg.length == 1
rs.execute(seg[0])
else
rs.execute(seg[0], seg[1])
end

end

 

가변인자로 넘겨받은 값들을 sql 의 바인드 변수값으로 넣어주려고 하는데 도무지 깔끔하게 안되더군요.

seg.join(“,”) 과 같은 식으로 값 분리해서 넘겨주어도 안되고 기타 등등 …
그런데 허무하게도 넘겨줄 때도 그냥 가변인자 방식으로 하면 되더군요. 이렇게 한 줄로.

rs.execute(*seg)

execute 메서드에 이리 넘겨주어도 알아서 잘 처리해줍니다.

공부하는 셈치고 dbi 라이브러리 소스 파일에서 execute 구현된 부분은 찾아보니

        def execute(*bindvars)

@handle.bind_params(*bindvars)
@handle.execute


@row = DBI::Row.new(column_names, column_types, nil, @convert_types)
#end
return nil
end

대충 저런 식으로 구현되어 있습니다. 역시나 sql 바인딩할 변수를 몇 개 넘겨줄지 모르니 가변인자를 쓴 듯.

내친 김에 execute 에서 가변인자를 또다시 넘겨 호출하는 bind_params 는 또 어떻게 구현되었나 찾아보았습니다.

       def bind_params(*bindvars)
bindvars.each_with_index {|val,i| bind_param(i+1, val, nil) }
self
end

이제 대략 응용할 방법 알 듯 합니다.

( 정말 혹시나 해서 첨언하자면 1.5 부터는 java 에서도 가변인자 지원합니다. void sum(int … i) 같은 식으로요. 역시나 배열로 처리됩니다 )

3. 수작업의 마지막 단계는 DB 에서 필요한 정보값들 구한 다음에 이 값들을 get 방식으로 구성해서 브라우저에서 웹서비스를 호출하는 것입니다.
루비에서 이 작업을 자동으로 처리하기 위해 HTTP 클라이언트 API 를 사용했습니다.
( http://ruby-doc.org/stdlib-1.9.3/libdoc/net/http/rdoc/Net/HTTP.html 여기보면 잘 정리되어 있습니다. )

params  = { :ModuleName => module_name, :InterfaceType => if_type, :TransactionStatus => “U”, :TransactionId => tran_id }
uri.query = URI.parse(URI.encode_www_form(params))

res = Net::HTTP.get_response(uri)

 

잘 되는 듯 싶더니 수시로 URI::InvalidURIError 에러가 나더군요.

원인 찾아보니 :TransactionId => tran_id 에서 trans_id 변수에 넘어가는 인자값이 종종 ‘103|8230032’ 과 같은 형태가 되는데 “|” 가 범인인 듯.

RFC 2396 section 2.4.3 에 이런 내용이 있다고 하네요.

Other characters are excluded because gateways and other transport agents are known to sometimes modify such characters, or they are used as delimiters.
unwise = “{” | “}” | “|” | “\” | “^” | “[” | “]” | “`”
Data corresponding to excluded characters must be escaped in order to be properly represented within a URI.

 

예전에도 이 문제 피해가기 위해 트릭 쓴 적 있었는데 오래되어서 기억이 전혀 안나서 또 괜한 고생.

해법은 역시나 너무 간단했는데 bad URI 에러니 문제되는 인자값을 get 방식으로 넘겨주지 않고 다른 방식으로 넘겨주면 되는 것, 그냥 post 방식으로 넘겨주면 됩니다.

앞에 링크한 문서에 post 방식예도 잘 설명되어 있으므로 더 이상의 설명은 패스. libcurl 등으로 cURL 을 사용하는 방법도 고려해볼 수 있을텐데 이것 역시 패스.

 

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s