다음은 Ruby의 제어 흐름(Flow of Control)에 대한 이야기이다.
Ruby의 흐름 제어
흐름 제어 쪽에서 알아볼 것은 말 그대로
Ruby에서 흐름을 제어하는 명령어에 대한 것을 말한다.
일반적인 if/elseif/else, while/for의 모습도 보이지만
다른 형태의 흐름 제어 명령어도 보인다.
기본적으로 if, elseif, else의 경우는
다른 언어와 큰 차이는 없어보이며
Python과 마찬가지로 블록을 사용하지 않고
end를 사용해 끝을 알리는 것 같다.
조금 특이한 것이 있다면 아닐 경우를
unless라는 명령어로 구분하는 부분이다.
다음으로 while과 until인데
사실 while이라는 명령어가 ~동안이라는 의미를 가지고 있기 때문에
익숙하지 않다면 자주 헷갈리는 부분이다.
Ruby의 경우는 until이라는 명령어가 있어서
until을 사용한다면, 가독성이 상승할 것 같다.
modifier form(수정자 폼)이라는 것도 있는데,
이 기능은 영어 형식에 대해
가독성을 높일 수 있게 만든 것이기 때문에
다른 언어권이면 잘 사용하지 않을 것 같다.
강의에서는 자연스러운 영어 처럼 읽을 수 있기 때문에
표현 방식이 풍부해질 수 있다고는 이야기한다.
놀랍게도 Ruby에서는 모든 것이 true를 반환한다고 한다.
단, fasle와 nil라는 객체를 빼고 말이다.
Ruby에서는 '==='의 명령어를 지원하는데,
'==='는 해당 문자열을 포함하는지와 같은
정규식을 활용할 때나
'=='와 똑같은 역할을 할 수도 있다.
심지어 정수 클래스(Integer)와 정수 값(21)을 비교할 경우에도
'==='을 사용할 수 있다.
다음으로 Case 표현에 관한 내용이다.
2가지 방법이 존재하는데,
if문을 활용할 때와 유사한 방식과 case ~ when로 값을 비교해 제어하는 방식이다.
전자의 경우 상단의 코드를 나타내는데,
'>='와 '=='를 활용해 제어 하지만
후자의 경우 하단의 코드를 나타내는데
'==='와 동일한 기능을 가진다.
이 '==='를 대소문자 평등 연산자라고 부르기도 한다고 하며,
객체를 비교할 때 ===를 자주 사용한다고 한다.
강의자는 뜬금 없이 자신이 거짓말을 했다고 고백하는데,
사실 Ruby에서는 For문을 잘 사용하지 않고,
each/times를 자주 사용한다고 한다.
하단의 코드는 for문을 활용하는 방법을 보여준다.
정리해보자면 흐름 제어에는 여러가지 방법이 있으며,
수정자 폼이라는 유용한 표현 방법과,
Non-nil 객체와, non-false라는 객체를 제외하고는 모두 true를 반환한다.
물론 모국어가 한국어인 나에게 수정자 폼(Modifier Form)이
지금 당장은 유용해 보이지는 않았다.
Function과 Method
Ruby에서는 모든 함수와 메소드는 클래스에 속한다고 한다.
따라서 이후 부터는 함수도 메소드르 부른다고 한다.
Ruby에서의 메소드 선언은 매우 유연하다고 할 수 있는데,
위와 같이 괄호를 빼고 선언해도 상관 없다.
이렇게 매우 유연한 언어들은
매개변수를 포함해 대개 데이터 타입 값을 선언하지 않는데
Ruby의 경우 Return 값 또한 딱히 명시하지 않아도 된다.
아마 이전에도 잠깐 언급되었듯이
Ruby는 모든 것을 객체로 보기 때문이라고 생각 된다.
만약 명시하지 않을 경우,
메소드의 마지막 코드를 반환 한다고 한다.
divide 메소드의 경우
위의 흐름 제어에서 나온 수정자 폼을 활용한 것을 볼 수 있다.
Ruby에서는 메소드 이름 끝에 ?와 !를 붙일 수 있는데
먼저 ?의 경우 일반적으로 부울 값을 리턴 한다.
위의 코드는 나눌 수 있는 값이면 true를
나눌 수 없는 값(0)이면 false를 리턴하는 메소드 인데,
결과 값을 보면 부울 값을 리턴하는 것을 확인할 수 있다.
다음으로 디폴트 인수에 대한 이야기로
매개 변수를 n = 5로 정의해서 디폴트 값을 설정할 수 있다.
위에서도 설명했듯이 return값을 명시하지 않아
끝 줄을 리턴하는 것을 주목해보자.
매개 변수에 *가 붙어 있어 포인터처럼 보이지만
포인터가 아니라 Java의 var args와 같이 인수가 작동하는 방식과 유사하다.
따라서 전달하고자하는 매개 변수가 많지만
얼마나 많은지에 대해 상관하지 않는다.
매개 변수들은 메소드 내에서 하나의 큰 배열 취급을 받는다고 한다.
위의 예제 코드를 보면 *number를 정의해서
3가지의 정수형 데이터를 넣은 것을 확인할 수 있다.
블록(Block)
블록이란 실행 중인 코드 덩어리로
중괄호 또는 do, end 키워드 사이에 전달하고
매개 변수로서 메소드에 전달 된다.
위의 코드와 같이 블록은
매개 변수 또는 인수를 받을 수도 있는데
파이프(||)사이에 해당 변수를 집어 넣으면 된다.
메소드에서 블록을 사용할 수도 있는데
암묵적인 방법(Implicit)과 명시적인 방법(Explicit)이 있다.
암묵적인 방법의 경우 block_given?과 yield를 사용해 블록을
호출(Call)해야만하며
명시적인 방법의 경우 매개 변수,
그리고 call 메소드를 활용해 블록을 호출 한다.
먼저 암시적인 방법의 경우
위의 코드와 같이 block_given?으로 블록인지를 판단하고
yield로 블록을 2번 호출하는 것을 볼 수 있다.
명시적인 방법의 경우 매개 변수를 통해
블록을 받아들일 것이라는 것을 정확히 명시하고 있다.
해당 매개 변수가 nil일 경우 블록을 호출하지 않으며,
nil이 아닐 경우 2번 블록을 호출하는 것을 확인해볼 수 있다.
파일 읽기, 쓰기
위 코드는 파일을 열어 한 라인씩
문자열을 출력하는 코드를 보여 준다.
do, end 키워드로 블록을 설정해주었고
chomp 메소드를 이용해 줄 바꿈 문자를 잘라내고.
split 메소드를 사용해 줄 바꿈 문자를 기준으로
문자열을 잘라낼 수도 있다.
만약 해당 파일이 존재하지 않는다면
에러 메시지를 보여주고 프로그램은 종료된다.
만약 갑자기 종료시키고 싶지 않다면,
예외(Exception)를 핸들링(설정) 해줄 수 있다.
rescue Exception => e ~ end 키워드를 사용해
변수 e로 예외 처리를 할 수 있다.
하지만, 단순히 파일을 찾을 수 없는 경우라면
간단하게 하단의 코드를 사용할 수도 있다.
또한 Ruby에서는 파일을 읽고 쓸때,
블록 내에 모든 작업을 수행하고
블록이 끝날 때 자동으로 닫기 때문에
개발자가 이런 걱정을 특별히 할 필요가 없다.
마지막으로 환경 변수에 관한 이야기 이다.
Editor는 현재 Sublime을 사용하고 있으므로
출력물이 subline이 출력되는 것을 확인할 수 있다.