티스토리 뷰

Things That Newcomers to Ruby Should Know에서 발췌한 내용들이다.


1. ruby를 실행할 때 -w 옵션을 주어 실행하면 실행시 발생하는 경고(warning)메시지를 볼 수 있다. 환경 변수(RUBYOPT)를 설정하여 ruby interpreter에 옵션을 전달할 수 있다.

2. irb라는 ruby interactive shell이 있으므로 디버깅이나 테스트 용으로 사용하면 편리하다.

3. ruby관련 문서는 ri를 이용하면 쉽게 볼 수 있다.
ri File # File object ri IO.open # IO.open method

4. 문서에서 "Klass#method"로 표기된 method는 instance method이고 "Klass.method"로 표기된 것은 class method이다. 이것은 단순히 표기법일 뿐이지 ruby syntax는 아니므로 혼동하면 안된다.

5. String#[Fixnum]은 문자열의 지정된 위치에 있는 ascii값을 반환하지 문자 그 자체를 반환하지 않는다. 예를 들어 "hello"의 두번째 문자인 "e"를 출력하기 위해 "hello"[1]과 같은 ruby expression은 "e"를 반환하지 않고 "e"의 ascii값인 101을 반환하게 된다. ascii값이 아닌 문자 자체를 반환 받고 싶다면 위치 인덱스 뿐 아니라 길이도 함께 주어야한다. 또는 ascii값을 문자로 바꾸는 Fixnum#chr 을 이용해도 된다.

  • "hello"[1] ==> 101

  • "hello"[1, 1] ==> "e"

  • "hello"[1].chr ==> "e"

  • ?e ==> 101 # 해당 문자의 ascii값을 구함.


6. Array.new(2, Hash.new)는 두개의 동일한 Hash object에 대한 reference를 두개 가지고 있는 배열을 만든다. 서로 다른 Hash object를 포함하고 있는 배열을 만들고 싶다면 map이나 collect method를 사용하면 된다.
arr = (1..2).map {Hash.new}

7. mutable(내용이 변할 수 있는) 객체를 해쉬의 키로 사용했다면 키가 변할 경우 해쉬 키의 인덱스를 재배치해야만 바뀐 키로 데이터를 찾을 수 있다.
s = "mutable"
arr = [s]
hsh = { arr => "object" }
s.upcase!
p hsh[arr] # nil
hsh.rehash
p hsh[arr] # "object"

8. file에서 데이터를 읽어서 숫자로 처리를 하려면 .to_i, .to_f method로 정수 또는 실수로 변환을 해야한다.

9. ruby에는 ++, --와 같은 increment, decrement operator가 없다. i++과 같은 것은 parse error가 발생하고 ++i와 같은 것은 무의미한 operation이다. ++ 두개는 양수에 양수라는 의미이기 때문이다. 마찬가지로 --i 역시 음수의 음수는 다시 양수 이므로 그냥 i가 된다. 증가, 감소를 하려면 i += 1, i -= 1을 이용하면 된다.

10. local변수와 블럭 내에서의 local변수가 같이 사용될 때 주의해야한다. 블럭 내의 파라메터로 전달되는 local변수와 같은 이름의 local변수가 블럭이 선언되기 전에 사용되었고 이름이 같다면 블럭 내에 전달된 local변수는 바깥 쪽에 선언된 local변수를 override하게 된다.
11. ruby에서는 logical operator가 동일한 두 개의 세트가 존재한다. [!, &&, ||]는 [not, and, or]와 같다. 주의할 점은 연산자 우선 순위인데 [!, &&, ||]는 [=, %=, ~=, /=,...)등보다 우선 순위가 높은 반면 [not, and, or]는 우선 순위가 낮다.
a = 'test'
b = nil
both = a && b # both == nil ----> both = (a && b)
both = a and b # both == 'test' ---> (both = a) and b
both = (a and b) # both == nil

12. 다음과 같은 문장이 있을 때
case obj
when obj_1
when obj_k

여기에서 비교를 위해서 === operator를 사용하게 된다. 이 경우 비교 순서는 obj_1 === obj 또는 obj_k === obj가 된다. obj === obj_1과 같은 순서로 비교 되지 않는다. 비교 연산자의 순서가 중요한 이유는 ===가 operator가 아니고 method이기 때문이고 객체에 따라서 다르게 작동할 수 있기 때문이다. obj_1 === obj 는 obj_1.===(obj) 와 같다. 즉 ===는 operator가 아니고 method이름이다. Module이나 Class에 정의된 ===는 비교 대상이 되는 객체가 같은 종류의 클래스 또는 상위 클래스 인지를 비교한다. Regexp에서 ===는 =~ 와 같다. Range에서의 ===는 범위 내에 포함이 되었는지를 알려준다.

13. method호출 시 ( 앞에 white space를 주지 않아야 한다. $VERBOSE == true인 경우에 경고 메시지가 나온다.

14. .(dot)은 가장 우선 순위가 높은 operator이다. 그래서 1.e6은 Fixnum타입인 1에 e6라는 method를 실행하는 것과 같다. 원하는 결과를 얻으려면 1.0e6와 같이 해야한다

15. "o..k"는 Range객체를 나타내지만 "[o..k]"은 Array객체를 나타낸다.

16. Ruby에서는 오직 nil과 false만이 false로 간주된다. 0 또는 "", '', [], {} 등은 모두 true이다.

17. Ruby에서 = operator는 객체에 대한 reference를 복사하는 것이다. a += b는 실제로 a = a + b로 간주되어 처리된다. (a += b는 a의 값에 b를 직접 더하는 것처럼 보이지만 실제로는 따로 계산을 한 뒤 a에 재할당을 한다는 것임) 이와 같이 ruby에서는 어떤 operation이 객체를 직접 변화시키는지 변화시키지 않는지 주의해야한다. (mutable인지 immutable인지 주의해야한다는 얘기임. ruby에서는 method이름 뒤에 !가 붙는 것들이 있는데 이 convention으로 mutable operation인지 immutable opeation인지 알 수 있다. !가 붙으면 mutable operation)
예를 들어 String객체에 다른 문자열을 더하는 operation으로 '< <' 와 '+='가 있다. 속도의 차이로 본다면 '<<'쪽이 '+='보다 빠르다. 왜냐하면 '<<'는 원본 문자열에 직접 다른 문자열을 더하는 것이고 '+='는 숫자 연산에서와 마찬가지로 '+'로 문자열을 더한 후 새로 생성된 문자열을 다시 할당하는 것이기 때문이다.

18. Ruby에서는 객체를 deep copy하는 방법이 없다. Deep copy를 하고 싶다면 marshaling/unmarshaling을 이용하면 된다.

19. Class변수는 클래스 계층을 따라 공유 된다. Child class에게도 공유가 되고 instance화된 객체들에게도 모두 공유가 된다. 하지만 하나의 예외가 있는데 class변수가 하위 class에 의해 초기화가 된 경우에는 공유되지 않고 별도의 변수처럼 작동하게 된다.
class Base
def initialize; @@var = 'base'; end
def base_set_var; @@var = 'base'; end
def base_print_var; puts @@var; end
endclass Derived < Base
def initialize; super; @@var = 'derived'; end # notice
def derived_set_var; @@var = 'derived'; end
def derived_print_var; puts @@var; end
end

d = Derived.new
d.base_set_var; d.derived_print_var # -> 'base'
d.base_print_var # -> 'base'
d.derived_set_var; d.derived_print_var # -> 'derived'
d.base_print_var # -> 'derived'

위의 소스를 보면 notice라고 된 부분에서 super를 호출하여 상위 클래스의 constructor가 먼저 실행되도록 하였다. 하지만 아래 소스를 보면 super를 호출하기 전에 @@var를 먼저 초기화를 했다. 출력되는 결과를 보면 알겠지만 아래와 같이 하위 클래스에서 먼저 클래스변수를 초기화한 경우에는 클래스 변수가 공유되지 않고 별도의 독립적인 영역을 가지게 된다.

class Base
def initialize;
@@var = 'base';
end
def base_set_var;
@@var = 'base';
end
def base_print_var;
puts @@var;
end
end

class Derived < Base
def initialize; @@var = 'derived'; super; end # changed
def derived_set_var; @@var = 'derived'; end
def derived_print_var; puts @@var; end
end

d = Derived.new
d.base_set_var; d.derived_print_var # -> 'derived'
d.base_print_var # -> 'base'
d.derived_set_var; d.derived_print_var # -> 'derived'
d.base_print_var # -> 'base'

20. \(backslash) 치환에 주의
str = 'a\b\c' # -> a\b\c
puts str.gsub(/\\/,'\\\\') # -> a\b\c
puts str.gsub(/\\/,'\\\\\\') # -> a\\b\\c
puts str.gsub(/\\/,'\\\\\\\\') # -> a\\b\\c
puts str.gsub(/\\/) { '\\\\' } # -> a\\b\\c
puts str.gsub(/\\/, '\&\&') # -> a\\b\\c

공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
«   2024/04   »
1 2 3 4 5 6
7 8 9 10 11 12 13
14 15 16 17 18 19 20
21 22 23 24 25 26 27
28 29 30
글 보관함