GnuSmalltalkUsersGuide:BasicChapter 03

From 흡혈양파의 번역工房
Revision as of 14:56, 9 December 2013 by Onionmixer (talk | contribs) (GSUG 제 3 장. 패키지 페이지 추가)
(diff) ← Older revision | Latest revision (diff) | Newer revision → (diff)
Jump to navigation Jump to search
제 3 장. 패키지

패키지

GNU Smalltalk는 다른 goodies를 먼저 로딩시켜야하는지 여부를 걱정할 필요 없이 컴포넌트를 (스몰토크의 매우 전형적인 용어로 goodies라 부른다) file in하도록 해주는 패키징 시스템을 포함한다.


패키징 시스템은 아래 (뻔하게도) 세 가지 장소에서 PackageLoader라는 스몰토크 클래스에 의해 구현되는데, 이 클래스는 packages.xml이라는 XML 파일로 된 패키지의 정보를 검색한다:


  • 커널 디렉터리의 부모 디렉터리; 설치된 packages.xml가 상주하는 곳으로, /usr/local/share/smalltalk 처럼 시스템 규모(system-wide)의 데이터 디렉터리 내에 위치한다;
  • 사용자별 패키지를 호스팅하는 .st/packages.xml 파일 내에 위치한다;
  • 마지막으로, 현재 이미지와 동일한 디렉터리 내 packages.xml이 될 수도 있다.


패키징 시스템을 이용해 무언가를 로딩하는 방법에는 두 가지가 있다. 첫 번째는 PackageLoader의 fileInPackage: 와 fileInPackages: 메서드를 사용하는 방법이다. 예를 들면 다음과 같다:

PackageLoader fileInPackages: #('Blox' 'Browser').
PackageLoader fileInPackage: 'Compiler'.


두 번째 방법은 가상 머신과 함께 설치되는 gst-load 스크립트를 사용하는 방법이다. 가령:

gst-load Browser Blox Compiler


위를 실행하면 GNU Smalltalk는 자동으로 아래를 file in할 것이다:

  • BloxTK, Blox에서 필요로 함
  • Blox, Browser에서 필요로 하기 때문에 가장 먼저 로딩됨
  • Parser, 명시되지 않지만 Browser와 Compiler가 필요로 함
  • Browser
  • Compiler (Blox는 이미 로딩되었기 때문에 건너뜀)


그리고 나면 스몰토크 이미지를 저장하고 마지막으로 종료할 것이다.


gst-load는 여러 옵션을 지원한다:


-I

--image-file

주어진 이미지 내부에 패키지를 로딩한다.


-i

--rebuild-image

처음부터 이미지를 빌드하고 그 안에 패키지를 로딩한다. –I로 명시된 이미지가 아직 존재하지 않을 때 유용하다.


-q

--quiet

스크립트의 출력을 숨긴다.


-v

--verbose

어떤 파일이 로딩되는지를 하나씩 보여준다.


-f

--force

명령 행에 주어진 패키지가 이미 존재하는 경우 재로딩한다. 자동으로 선택된 전제조건(prerequisite)에는 적용되지 않는다.


-t

--test

패키지 검사도구(testsuite)를 설치 전에 실행하고, 검사가 실패하면 실패와 함께 종료하라. 최근 검사도구는 패키지와 함께 이미지에 위치하지만 향후 버전에는 변경될 수도 있다.


-n

--dry-run

이미지를 로딩 후 저장하지 말라.


--start[=ARG]

패키지에서 식별한 서비스를 시작하라. 인자가 주어진 경우 명령 행에 하나의 패키지만 명시할 수 있다. 최소 하나의 패키지가 시작(startup) 스크립트를 명시할 경우 gst-load는 종료하지 않을 것이다.


이 시스템에 대한 지원을 제공하기 위해서는 GNU Smalltalk goodies에 작은 파일을 (주로 package.xml 라고 불림) 줄 수 있는데 이는 다음과 같은 모양을 한다:

<packages>
    <package>
    <name>BloxGTK</name>
    <namespace>BLOX</namespace>
    <directory>blox-gtk</directory>
    <! -- prereq 태그는 이것보다 앞에 로딩되어야 하는 패키지를 식별한다.-->
    <prereq>GTK</prereq>
    <! -- provides 태그는 이것이 로딩되고 나면 로딩할 필요가 없는 패키지를 식별한다.-->
    <provides>BLOX</provides>
    <! -- filein 태그는 이 패키지를 구성하는 패키지들을 식별하는데 이러한 패키지들은 아래 순서로 로딩되어야 한다.-->
    <filein>BloxBasic.st</filein>
    <filein>BloxWidgets.st</filein>
    <filein>BloxText.st</filein>
    <filein>BloxExtend.st</filein>
    <filein>Blox.st</filein>
    <!-- file 태그는 이 패키지의 배포를 구성하는 패키지들을 식별한다.-->
    <file>Blox.st</file>
    <file>BloxBasic.st</file>
    <file>BloxWidgets.st</file>
    <file>BloxText.st</file>
    <file>BloxExtend.st</file>
    </package>
</packages>


그 외 다른 태그도 존재한다:

module 동적 공유 객체를 로드하고 그 안에 gst_initModule 함수를 호출한다. 모듈은 함수를 등록할 수 있으므로 스몰토크 코드는 그 함수를 호출할 수 있고, 스몰토크 객체와 대화 또는 조작할 수 있다. Sockets 패키지는 모듈을 이용해 소켓(socket) 함수에 브릿지(bridge)를 제공한다.

library 동적 공유 객체를 로드하고 그 안에 함수를 등록하여 스몰토크 코드로부터 호출이 가능하다. GTK 패키지는 이러한 방식으로 GTK+ 라이브러리를 등록하므로 바인딩은 이를 이용할 수 있다.

callout 이름이 태그 내부에 있는 C 함수를 스몰토크 코드로부터 호출할 수 있는 경우에만 패키지를 로드하도록 지시한다.

sunit 패키지를 검사하기 위해 gst-sunit가 (40 페이지의 3.7절 [Suit]를 참조) 실행될 테스팅 스크립트를 명시한다. 스크립트가 명시된 경우 패키지는 전제조건들 사이에 SUnit를 열거해야 한다.

start 패키지에서 구현되는 서비스의 실행을 시작하기 위해 gst-load와 gst-remote가 실행될 스몰토크 스크립트를 명시한다. 스크립트를 실행하기 전에 %1은 nil 또는 String 리터럴로 대체된다.

stop 패키지에서 구현되는 서비스를 종료하기 위해 gst-remote가 실행될 스몰토크 스크립트를 명시한다. 스크립트를 실행하기 전에 %1는 nil 또는 String 리터럴로 대체된다.

test 패키지를 검사하기 위해 gst-sunit에 의해서만 로드되는 하위패키지를 명시한다. 하위패키지는 (file, filein, sunit을 포함해) 임시 태그를 포함할 수는 있으나 name은 포함할 수 없다. SUnit 패키지는 암묵적으로 테스팅 하위패키지의 전제조건으로 만들어지고, directory와 namesapce의 기본값은 외부(outer) 패키지에 주어진 값이다.


자신의 패키지를 설치하기 위해서는 아래만 실행하면 된다.

gst-package path/to/package.xml


gst-package는 스몰토크 스크립트로서, 현재 이미지 디렉터리에 .star archive를 생성함과 동시 file 태그에 명시된 파일들도 생성할 것이다. 기본적으로 패키지는 시스템 규모의 패키지 디렉터리에 위치한다; --target-directory 옵션을 이용해 다른 곳에서 .star 파일을 생성할 수 있다.


이 방법이 아니라면 gst-package를 이용해 skeleton GNU 스타일 소스 트리를 생성하는 수도 있다. 이는 GNU Smalltalk의 설치 경로를 찾는 configure.ac와 모든 표준 Makefile 대상을 지원하는 Makefile.am 을(make install과 make dist도 포함해) 포함한다. 이를 위해서는 소스 트리의 최상단이 되는 디렉터리로 가서 아래를 입력하라.

gst-package –prepare path1/package.xml path2/package.xml


이런 경우, 생성된 구성 스크립트와 Makefile은 더 많은 gst-package의 기능을 사용할 것이나 아직 문서화되지는 않았다. GNU Smalltalk makefile은 이와 비슷하게 gst-package를 사용하여 패키지를 설치하고 배포판 타르볼(distribution tarball)을 준비한다.


본장의 나머지 부분에서는 GNU Smalltalk에서 제공하는 패키지의 일부를 논해보고자 한다.


Blox

Blox는 GUI 구성 요소(building block) 툴 킷이다. Blox는 모든 플랫폼에 공통적인 플랫폼의 네이티브(native) GUI 툴킷의 상단에 있는 추상화이다. Blox 인터페이스에 작성한다는 말은 당신의 GUI 기반 애플리케이션이 Blox가 지원되는 플랫폼이라면 어느 플랫폼으로든 이식 가능함을 의미한다.


BLOX 이름공간에 상주하고 GNU Smalltalk Library Reference의 "Graphical users interfaces with BLOX"절에 문서화된 내용인 Blox 클래스는 다른 툴킷에 대한 래퍼(wrapper)역할을 하여 필요한 이식성 계층(portability layer)를 구성한다; 최근 유일하게 지원되는 것은 Tcl/Tk이지만 Blox의 대안 버전, 즉, Gtk+나 GNOME을 기반으로 하는 버전이 고려되고 있으며, 향후에는 Tcl/Tk를 대체할지도 모른다.[1][2] 위젯을 재작성하고 각 플랫폼마다 지원하는 대신 Blox는 단순히 다른 툴킷에게 그렇게 하도록 요청한다 (현재 Blox는 표준 Tcl 8.0 환경으로 유효한 Tcl 코드를 전달한다); 사용되는 운영체제의 추상화가 GNU Smalltalk로부터 추출된다.


툴킷을 포함해 browser 디렉터리에 브라우징 시스템이 있는데, 이는 프로그래머가 기존 클래스의 소스 코드를 보고, 기존 클래스와 메서드를 수정하며, 클래스와 메서드에 대한 상세한 정보를 얻고, 브라우저 내에서 코드를 평가하도록 해준다. 또한 단순한 디버깅 툴도 몇 가지 제공된다. Inspector 창은 프로그래머가 객체의 표현을 그래픽하게 검사하고 수정하도록 해주며, walkback 인스펙터는 프로그램이 오류에 직면할 때 역추적(backtrace)을 표시하도록 고안되었다.


Transcript 전역 객체는 stdout로 인쇄하는 대신 트랜스크립트창으로 인쇄를 다시 전송하고, 콘솔 read-eval-print(읽고 계산하고 출력하는) 루프와 달리 워크스페이스와 트랜스크립트창은 다중 평가에 걸쳐 살아남는 변수를 지원한다:

a := 2 "Do-it"
a + 2 "Print-it: 4 will be shown"


이 브라우저는 Brad Diller가 1993년 정도에 작성해 개발한 Xt 기반의 버전에서 진화된 것이다 (bdiller@docent.com). 그의 초기 구현은 ParcPlace의 모델-뷰-컨트롤러(MVC) 메시지 인터페이스를 사용하여 발생할 수 있는 저작권 침해와 관련된 법적 문제로 인해 Richard Stallman와 그는 MVC의 의존성 메커니즘보다 더 유연하고 강력한 윈도우 업데이트 방식을 새로 고안하였는데, 이 덕분에 모든 MVC 요소를 구현으로부터 제거할 수 있었다.


이후 코드는 향상되어 더 나은 클래스 디자인을 이용하고 (예: Brad는 구체화되어야 하는 클래스에 대해 Dictionaries를 사용함), 미적으로 더 매력적이며 (새 Blow 텍스트 위젯을 활용하여 코드 브라우저는 구문 강조와 함께 향상됨), 더 완전해졌다 (인스펙터에 다중 "뷰" 추가, 이름공간 지원, 완전한 디버거).


브라우저를 시작하려면 단순히 아래를 입력하면 된다:

gst-blox


이는 여느 요청된 패키지든 로드할 것이며, 만일 성공 시 Smalltalk 라는 메뉴가 있는 워크시트 창이 화면의 좌측 상단에 나타날 것이다.


Smalltalk-in-Smalltalk 라이브러리

Smalltalk-in-Smalltalk 라이브러리는 스몰토크 코드를 살펴보고, 후에 실제로 생성할 수 있는 스몰토크 클래스의 모델을 구성하며, 이미지 변경내용을 분석 및 실행하고, 이상한 코드를 찾아내며, 반복 변경을 자동으로 실행하기 위한 클래스 집합이다. 이러한 패키지는 스몰토크의 반영적 기능을 놀랍도록 향상시킨다.


시스템의 기본 부분은 RBProgramNode의 서브클래스의 인스턴스 형태로 파스 노드를 생성하는 재귀적 하향 파서(recursive-descent parser)이다.


파서의 극적인 유연성은 세 가지 방식으로 활용이 가능한데, 세 가지 방법 모두 배포 시 이용 가능한 소스 코드에서 보여준다:

  • 첫째, 액션은 파서 자체에서 하드코딩되지 않는다: 파서는 파스 트리는 생성한 후 서로 다른 RBParser 서브클래스에서 덮어쓸 수 있는 RBParser 내 메서드들에게 트리를 전달한다. 이는 컴파일러 자체가 실행하는데, 여기서 RBParser의 서브클래스는 (STFileInParser 클래스) STCompiler 클래스에게 파스 트리를 전달한다.
  • 둘째, "방문자(visitor)" 패턴의 구현이 제공되어 파스 트리가 생성되는 과정을 처리하도록 도와준다; 이러한 접근법은 RBFormatter 클래스 내 스몰토크 pretty-printer, 브라우저와 함께 포함된 구문 강조 엔진과 컴파일러가 잘 보여준다.
  • 파서는 ParseTreeSearcher와 ParseTreeRewrite 클래스를 통해 복합 트리 검색과 재기록(rewrite)을 실행한다.


또한 GNU Smalltalk 특정적인 애플리케이션 두 개가 라이브러리 상에 생성되었다. 첫 번째는 스몰토크 자체에 작성된 스몰토크 메서드를 위한 컴파일러(compiler)로, 그 소스 코드는 GNU Smalltalk 가상 머신에 대해 훌륭한 통찰력을 제공한다.


두 번째는 자동 문서추출기로, packages/stinst/compiler/STLoader.st 와 packages/stinst/compiler/STLoaderObjs.st 두 파일에 포함되어 있다. 라이브러리를 로딩할 수 없을 때에도 (예: BLOX가 실행 중인 X 서버를 요한다) Texinfo 파일을 생성할 수 있으려면 스몰토크 소스 코드가 해석되고, 읽어오는 클래스와 메서드에 대한 객체가 생성된다; 이후 다형성 덕분에 GNU Smalltalk의 ClassPublisher (packages/stinst/doc/Publish.st에서 찾을 수 있음)로 넣을 수 있는 일반 클래스와 정확히 같은 방식으로 이러한 일들을 취급할 수 있다.


데이터베이스 연결성

GNU Smalltalk는 데이터베이스의 연결을 위한 지원을 포함한다. 최근 이러한 지원은 SQL 선택 쿼리로부터 결과 집합을 검색하고 SQL 데이터 조작 쿼리를 실행하는 것으로 제한되어 있다; 하지만 향후에는 SQL의 사용을 숨기는 전체 객체 모델을 이용할 수 있을 것이다.


사용 중인 데이터베이스 관리 시스템과 독립적인 클래스는 패키지 DBI에 상주하는 반면 드라이버는 DBI를 전제 조건으로 갖는 구분된 패키지에 상주한다; 최근 드라이버는 MySQL과 PostgreSQL에 대해 공급되는데, 각각 DBD-MySQL과 DBD-PostgreSQL 패키지에 위치한다.


라이브러리의 사용은 꽤 간단하다. 쿼리를 실행하기 위해서는 데이터베이스로 연결을 생성하고, 그 연결 상에 문(statement)을 생성하여, 자신의 쿼리를 실행한다. 예를 들어, 로컬호스트(localhost) 상에 있는 test 데이터베이스로 연결하고 싶다고 치자. 나의 사용자 이름은 doe이고 비밀번호는 mypass다.

| connection statement result |
    connection := DBI.Connection
    connect: 'dbi:MySQL:dbname=test:host=localhost'
    user: 'doe'
    password: 'mypass').


DBMS 특정적 클래스는 DBI의 하위 이름공간에 상주하는 반면 DBMS 독립적 클래스는 DBI에 상주함을 볼 수 있다. 여기서 쿼리를 실행하는 방법은 다음과 같다.

statement := connection execute: 'insert into aTable (aField) values (123)'.


반환되는 결과는 ResultSet 다. 일자 쿼리를 위해 객체는 영향을 받는 ows 수를 리턴한다. 읽기 쿼리의 경우 (예: 선택 쿼리), 결과 집합은 표준 스트림 프로토콜을 (결과 스트림으로부터 각 열을 읽어내기 위한 next, attend) 지원하고, 열 정보의 컬렉션을 공급할 수도 있다. 이들은 ColumnInfo) 의 인스턴스들로, 리턴된 열의 유형, 크기, 다른 특징들을 설명한다.


ResultSet의 일반적인 사용은 다음과 같을 것이다:

| resultSet values |
[resultSet atEnd] whileFalse: [values add: (resultSet next at: 'columnName') ].


국제화와 지역화 지원

여러 국가와 문화는 통신 방법에 대해 다양한 규칙을 갖고 있다. 이러한 규칙은 일자와 시간을 표현하는 방식처럼 간단한 것에서부터 구사 언어와 같이 복잡한 것까지 다양하다. 규칙의 선택을 준수하도록 작성되었다는 점을 감안 시 프로그램은 사용자가 선호하는 규칙을 따를 것이다. GNU Smalltalk는 당신의 작업을 용이하게 해줄 두 가지 패키지를 제공한다. I18N 패키지는 국제화와 다국어화를 포함한다; 좀 더 가벼운 Iconv 패키지는 다국어화만 포함시키는데, 다국어화는 올바른 국제화의 전제 조건이기 때문이다.


소프트웨어의 다국어화는 프로그래밍이 세계 모든 부분의 언어를 지원할 수 있어야 한다는 의미다. 특히 다중 바이트 문자 집합과 (예: UTF-8), 코드 포인트가(ASCII 값과 동일) 127가 넘는 유니코드 문자의 이해를 포함한다. 이를 위해 GNU Smalltalk는 그 데이터를 32-bit 유니코드 값으로 보관하는 UnicodeString 클래스를 제공한다. 또한 Character는 유니코드에서 이용 가능한 1,000,000 코드 포인트 이상을 지원한다.


I18N 패키지의 로딩은 비 ASCII 유니코드 문자를 해석하고 트랜스코딩하는 EncodedStream 클래스[3]를 통해 이러한 지원을 향상시킨다. 이러한 지원은 대부분 투명하게 이루어지는데, Character, UnicodeCharacter, UnicodeString 기반 클래스가 그것을 사용하도록 개선되었기 때문이다. asString 또는 printString을 Chracter와 UnicodeString의 인스턴스로 전송 시 유니코드 문자를 변환시켜 현재 지역에서 올바르게 인쇄될 것이다. 예를 들어, I18N 패키지가 로딩되면 '$<279>printN1' 은 위에 점이 찍힌 작은 라틴어 문자 'e' 를 인쇄할 것이다.


이와 마찬가지로 String 이나 ByteArray 객체를 단일 메서드 호출를 이용해 유니코드로 변환하는 수도 있다. 현재 지역의 인코딩이 UTF-8인 경우, '#[196 151] asUnicodeString'은 위와 동일한 문자로 된 유니코드 문자열, 즉, 위에 점이 찍힌 작은 라틴어 문자 'e'를 리턴할 것이다.


다국어화 지원의 구현은 아직 완전하지 못하다. 가령 asLowercase, asUppercase, isLetter와 같은 메서드는 아직 유니코드 문자를 인식하지 못한다.


따라서 주의를 기울이지 않으면 유니코드 문자를 사용 시 프로그램에 버그가 생길 것이다. 특히 문자는 == [4]과 비교되어선 안 되며, nextPut: 보다는 display: 로 스트립 상에 인쇄되어야 한다.


또한 문자는 codePoint 라는 클래스 메서드를 이용해 생성할 필요가 있다: 그 유니코드 값을 참조하는 경우 codePoint: 또한 스몰토크를 위한 ANSI 표준에서 수용하는 문자를 생성하는 유일한 메서드가 된다. 대신 특정 인코딩에서 바이트를 참조하는 경우라면 value: 메서드를 사용해야 한다. 이런 미묘한 차이는 아래에서 마지막 두 개의 예가 실패할 것을 의미한다.


"올바름. Strings로 #value: 를 사용하고, UnicodeString로 #codePoint: 를 사용하라."

String with: (Character value: 65)
String with: (Character value: 128)
UnicodeString with: (Character codePoint: 65)
UnicodeString with: (Character codePoint: 128)


"올바름. 0-127 범위의 문자에만 작용, 방어적 프로그래밍으로 간주될 수도 있음. UnicodeString을 이용 시 항상 #codePoint: 를 원할지도 모른다."

String with: (Character codePoint: 65)


"불확실함, 0-127 범위의 문자에만 효과가 있다. UnicodeString을 이용 시 항상 #codePoint: 를 원할 것이다."

UnicodeString with: (Character value: 65)


"실패, String에 상위 문자의 사용을 시도한다"

String with: (Character codePoint: 128)


"실패, 유니코드 문자열에 인코딩의 사용을 시도한다"

UnicodeString with: (Character value: 128)


대신 소프트웨어의 국제화는 프로그래밍이 사용자가 가장 좋아하는 규칙으로 조정할 수 있음을 의미한다. 이러한 규칙은 꽤 복잡해질 수도 있다: 예를 들어, 사용자는 대부분 목적에는 "스페인-까스띨야(espana-castellano)" 지방어를 명시할 수도 있지만 화폐 양식에는 '미국-영어(use-english)' 지역어를 명시하는 수도 있다: 스페인어를 말하는 미국인이 스페인어로 작업을 하되 화폐는 미국 달러로 표현한다면 이치에 맞을 것이다. 이러한 시스템은 단순한 동시 매우 완전함을 볼 수 있다. 하지만 이번 매뉴얼은 사용자가 이러한 규칙에 맞게 어떻게 시스템을 준비하는지를 철저히 논하기엔 올바르지 않다; 충분한 정보는 운영체제 매뉴얼 또는 GNU C 라이브러리의 매뉴얼을 참고하라.


GNU Smalltalk는 지역의 개념, 규칙의 집합 개념을 ISO C로부터 상속 받았는데, 그 개념은 목적마다 하나의 규칙이 해당하는 규칙 모음을 상속 받고, 각 목적을 I18N 패키지에서 정의한 스몰토크 클래스로 매핑하며, 이러한 클래스는 Locale을 루트로 하는 작은 계층구조를 형성한다:

  • LcNumeric 포맷 구성원; LcMonetary와 LcMonetaryISO는 화폐량을 구성한다.
  • Lctime은 일자와 시간을 형성한다.
  • LcMessage는 당신의 프로그램 출력을 해석한다. 물론 패키지가 자동으로 프로그램의 출력 메시지를 다른 언어로 번역할 수는 없다: 사용자의 선호 언어로 출력을 지원하는 유일한 방법은 해당 메시지를 수동으로 번역하는 방법이다. 패키지는 물론 쉽게 다중 언어로 번역을 처리하도록 메서드를 제공한다.


I18N 패키지의 기본 사용은 단일 선택자인 물음표(?)를 수반하는데, 이는 스몰토크 이진 메시지에서 유효한 문자로 사용되는 경우가 드물다. 물음표 선택자의 의미는 "당신의 규칙에 따르면...어떻게 말하는가?"와 같다. ?는 Locale의 서브클래스의 구체적 인스턴스로 전송하거나, 클래스 자체로 전송할 수 있다; 이런 경우 기본 지역의 규칙이 (환경 변수를 통해 명시된) 적용된다. 가령 Lctime ? Date today 또는 germanMonetaryLocale ? account balance라고 말할 수 있겠다. 이 구문은 처음엔 혼란스러울지 모르지만 일관성과 전반적 단순성 때문에 편리한 것으로 나타난다.


? 가 여러 클래스에 어떻게 작용하는지 살펴보자:

? aString [LcTime 상의 메서드]

일자, 시간 또는 타임 스탬프를 (DateTime 객체) 포맷팅한다.


? aString [LcNumber 상의 메서드]

숫자를 포맷팅한다.


? aString [LcMonetary 상의 메서드]

금전 가치를 화폐 기호와 함께 포맷팅한다.


? aString [LcMonetaryISO 상의 메서드]

금전 가치를 ISO 화폐 기호와 함께 포맷팅한다.


? aString [LcMessages 상의 메서드]

명시된 파일로부터 번역을 검색하는 금전 가치를 포맷팅한다.


? aString[LcMessagesDomain 상의 메서드]

주어진 문자열의 번역을 검색한다.[5]


이 두 개의 패키지는 유니코드를 위한 향상된 포맷팅 옵션 지원과 함께 여러 문자 집합 간 변환을 포함해 훨씬 더 많은 기능성을 제공한다. 더 상세한 정보는 GNU Smalltalk Library Reference 의 "Multilingual and international support with Iconv and I18N" 절을 참고하길 바란다.


한편 패키지가 사용하는 로컬(locale)의 표현은 C 라이브러리와 정확히 같아서 여러 장점이 있다: GNU Smalltalk 관리자는 로컬 데이터를 유지해야 하는 짐을 덜 수 있다; GNU Smalltalk의 사용자는 동일한 데이터에 대한 두 개의 복사본을 갖고 있을 필요가 없어진다; 마지막으로 최종 사용자에게 여러 국제화된 프로그램에서 책임지는 규칙의 획일성이 보장된다.


뿐만 아니라 번역된 문자열의 표현은 GNU gettext 라이브러리에서 채택하는 표준 MO 파일 포맷이다.


Seaside 웹 프레임워크

Seaside는 고도로 상호작용적인 웹 애플리케이션을 빠르고, 재사용 가능하며, 관리 가능하게 빌드하기 위한 프레임워크다. Seaside의 기능으로는 콜백 기반의 요청 처리, 계층구조적 (구성요소 기반) 페이지 디자인, 복잡한 작업 흐름을 쉽게 구현하기 위한 모달 세션(modal session) 관리가 포함된다.


간단한 Seaside 구성요소는 아래와 같은 모양을 한다:

Seaside.WAComponent subclass: MyCounter [
    | count |
    MyCounter class >> canBeRoot [ ^true ]
    initialize [
        super initialize.
        count := 0.
        ]
        states [ ^{ self } ]
        renderContentOn: html [
            html heading: count.
            html anchor callback: [ count := count + 1 ]; with: '++'.
            html space.
            html anchor callback: [ count := count - 1 ]; with: '--'.
    ]
]
MyCounter registerAsApplication: 'mycounter'


대부분의 경우 백그라운드 가상 머신에서 Seaside를 실행할 것이다. 가장 먼저 Seaside 패키지를 아래와 같이 새 이미지에 로드해야 한다:

$ gst-load -iI seaside.im Seaside Seaside-Development Seaside-Examples


이후에 아래 명령 중 하나를 이용해 Seaside를 시작할 수 있다.

$ gst-load -I seaside.im --start Seaside

$ gst-remote -I seaside.im --daemon --start=Seaside


그러면 http://localhost:8080/seaside에서 페이지 제공을 시작한다. 앞 명령은 포어그라운드에서 서버를 시작하는 반면 두 번째 명령은 가상 머신에서 실행시켜 사용자가 gst-remot의 호출을 이용해 제어할 수 있다. 가령 당신은 아래 명령을 각각 이용해 Seaside 페이지 제공을 중단시키고 서버를 종료할 수 있다:

$ gst-remote --kill

$ gst-remote --stop=Seaside


Swazoo 웹 서버

Swazoo (Smalltalk Web Application Zoo)는 무료 스몰토크 HTTP 서버로서, 정적인 웹 서빙과 완전한 기능의 웹 요청 해결 프레임워크를 모두 지원한다.


아래를 이용해 서버를 시작하거나,

$ gst-load --start[=ARG] Swazoo


아래를 이용해 백그라운드 GNU Smalltalk 가상 머신으로 로딩할 수도 있다:

$ gst-remote --start=Swazoo[:ARG]


주로 Swazoo 를 처음 시작하면 ARG는 swazoodemo (단순히 "Hello, World!" 서블릿을 시작)이거나, 아래와 같은 구성 파일로의 경로가 된다:

<Site name: 'hello'; port: 8080>
    <CompositeResource uriPattern: ''/''>
        <HelloWorldResource uriPattern: ''hello.html''>
    </CompositeResource>
</Site>


첫 단계가 끝나면 ARG는 아래 의미를 취할 수 있다:

  • 모두 누락될 경우 서버에 등록된 모든 사이트가 시작된다;
  • 숫자일 경우 해당 포트 상의 서버에 등록된 모든 사이트가 시작된다;
  • 구성 파일명일 경우 서버 구성은 해당 파일로부터 로딩된 것으로 대체된다;
  • 그 외 다른 문자열인 경우 ARG라는 사이트가 시작된다.


또한 백그라운드 서버는 아래를 이용해 중단할 수 있다:

$ gst-remote --stop=Swazoo[:ARG]


여기서 ARG 는 구성 파일이 된다는 점을 제외하면 동일한 의미를 지닌다.


뿐만 아니라 WebServer 패키지는 오래된 웹 서버 엔진을 구현하는데, 이는 현재 Swazoo로 대체되었다. 이는 GPL'ed WikiWorks 프로젝트를 기반으로 한다. GNU Smalltalk로 이식 외에도 코드에는 여러 내용이 변경되었는데, 클래스의 재팩토링, 향상된 모양, 인증 지원, 가상 호스팅, HTTP 1.1 준수를 포함한다.


SUnit 테스팅 패키지

SUnit 는 스몰토크에서 테스트 케이스를 작성하고 실행하기 위한 프레임워크로서, 본래 익스트림 프로그래밍[6]의 선구자인 Kent Beck에 의해 작성되었다. SUnit는 스몰토크에서 테스트를 작성하고 결과를 확인하도록 해준다; 이러한 접근법은 테스터가 간단한 스몰토크 프로그램을 작성할 수 있어야 한다는 단점이 있지만 결과적 테스트는 매우 안정적이다.


아래에서 SUnit의 철학과 그 사용 설명을 싣고자 하는데, 본문의 내용은 Kent Beck이 SUnit를 설명한 논문에서 발췌한 내용이다.


어디서부터 시작해야 할까?

테스팅은 불가능한 업무들 중 하나다. 물론 당신은 완벽하게 진행하여 소프트웨어가 확실히 작동하길 원할 것이다. 반대로 가능한 프로그램 상태 수는 너무나 커서 그 조합을 모두 검사하기가 불가능하다.


무엇을 테스트하는지 모호해지면 시작을 할 수가 없다. 행위가 예측 가능한 단일 구성부터 시작하는 편이 나을 것이다. 소프트웨어의 경험이 늘어나면 구성 목록을 추가할 수 있을 것이다.


그러한 구성을 픽스쳐(fixture)라고 부른다. Floats를 검사하기 위한 픽스쳐의 두 가지 예로 1.0과 2.0를 들 수 있다; Arrays의 검사를 위한 두 개의 픽스쳐는 #( )과 #(1 2 3)이 된다.


픽스쳐를 선택함으로써 당신은 검사 대상과 검사 제외 대상을 말할 수 있다. 객체 무리에 대한 완전한 테스트 집합은 많은 픽스쳐를 가질 수 있고, 그들 각각은 다양한 방식으로 검사될 것이다.


테스트 픽스쳐를 디자인하기 위해서는 아래를 실행해야 한다.

  • TestCase 서브클래스
  • 픽스쳐 내 알려진 각 객체에 대해 인스턴스 변수 추가하기
  • 변수를 초기화하도록 setUp를 오버라이드하기


테스팅의 단일 유닛(single unit)을 어떻게 표현하는가?

당신은 메시지를 픽스쳐로 전송한 결과를 예측할 수 있다. 그러한 예측 가능한 상황을 어떻게든 표현할 필요가 있다. 이를 가장 쉽게 표현하는 방법은 상호작용을 통해서이다. 픽스쳐에 인스펙터를 열고 그 곳에 메시지를 전송하기 시작한다. 이 방법에는 두 가지 결함이 있다. 첫째, 동일한 픽스쳐로 메시지를 계속 전송한다. 테스트가 객체를 엉망으로 만드는 것으로 밝혀질 경우 설사 코드가 올바르더라도 그에 잇따른 모든 테스트도 실패하기 마련이다.


더 중요한 것은, 대화형 테스트를 다른 사람에게 쉽게 전달할 수 없다는 사실이다. 누군가에게 당신의 객체를 전달할 경우 이를 테스트할 수 있는 유일한 방법은 당신을 초대해서 검사하는 방법뿐이다.


각 예측 가능한 상황을 고유의 픽스쳐가 있는 객체로 표현함으로써 두 테스트는 서로를 절대 방해하지 않을 것이다. 또한 테스트를 다른 사람이 실행하도록 쉽게 제공할 수 있다. 예측 가능한 픽스쳐의 반응을 메서드로서 표현하라. 그리고 메서드를 TestCase 클래스로 추가하고, 메서드 내에서 픽스쳐를 자극(stimulate)하라.


예측되는 결과를 어떻게 테스트하는가?

대화형으로 테스트하고 있다면 자신의 객체를 인쇄하고 검사함으로써 예측 결과를 직접 확인한다. 테스트는 자신만의 객체에 존재하므로 계획에 따라 문제를 검색할 방법이 필요하다. 이를 성취하는 방법으로는 테스팅 로직과 함께 표준 오류 처리 메커니즘을 (#error:) 이용해 오류를 신호로 보내는 방법이 있다:

2 + 3 = 5 ifFalse: [self error: 'Wrong answer']


테스트를 할 때는 가령 2와 3의 합이 6으로 나오는 것과 같이 자신이 확인하는 오류를, 바운드 또는 메시지 밖의 서브스크립트가 이해되지 않는다는 등의 예측하지 못했던 오류로부터 구별하고자 할 것이다.


예측하지 못한 오류에 대해 당신이 할 수 있는 일은 그다지 많지 않다 (무언가를 했다면 오류는 더 이상 예측 불가능하지 않을 것이다). 치명적 오류가 발생하면 프레임워크는 테스트 케이스의 실행을 중단하고 다음 테스트 케이스를 실행한다. 각 테스트 케이스는 고유의 픽스쳐를 갖고 있으므로 이전 케이스에서 발생한 오류는 다음 케이스에 영향을 미치지 않을 것이다.


테스팅 프레임워크는 Block을 인자로 취하는 #should: 메서드를 제공함으로써 예측된 값을 간단히 검사하도록 만들어준다. Block이 true로 평가되면 모든 것은 괜찮다. 그렇지 않을 경우 테스트 케이스는 실행을 중단하고 실패가 기록되며, 다음 테스트 케이스가 실행된다.


따라서 당신은 검사를 Boolean으로 계산하는 Block으로 바꾸어 Block을 매개변수로서 #should: 로 전송해야 한다.


예제에서 객체를 빈 Set로 추가함으로써 픽스쳐를 자극한 후에 그것이 내부에 존재하는지 검사하고 확보해야 한다:

SetTestCase>>#testAdd
    empty add: 5.
    self should: [empty includes: 5]


TestCase>>#should: 에는 변형체(variant)가 있다. TestCase>>#shouldnt: 는 Block 인자가 true로 계산 시 테스트 케이스의 실패를 야기한다. 이것이 존재하는 이유는 (. . .) not을 사용할 필요가 없도록 하기 위함이다.


테스트 케이스를 여기까지 진행했다면 이제 실행해도 좋다. TestCase 서브클래스의 인스턴스를 생성하여 테스팅 메서드의 선택자를 제공하라. 결과가 되는 객체로 run을 전송하라:

(SetTestCase selector: #testAdd) run


실행이 완료되면 시스템이 작동한 것이다. walkback이 발생하면 무언가 잘못된 것이다.


서로 다른 다수의 테스트 케이스를 어떻게 수집하고 실행하는가?

두 개의 테스트 케이스를 실행하는 즉시 두 가지가 자체가 아니라 서로의 것을 실행하길 원할 것이다. 이 때는 테스트 케이스를 생성하여 실행하도록 여러 표현식을 연결시킬 수 있겠다. 하지만 "여기서 약간의 케이스와 저기서 약간의 케이스"를 실행하려하면 막힐 것이다.


테스팅 프레임워크는 다수의 테스트를 표현하도록 TestSuite라는 객체를 제공한다. TestSuite는 테스트 케이스 집합을 실행하고, 그 결과를 한 번에 보고한다. 다형성의 장점을 취해 TestSuites는 다른 TestSuites를 포함할 수 있으므로, 당신은 더 높은 수준으로 된 검사도구(suite)를 생성함으로써 Joe의 테스트와 Tammy의 테스트를 합할 수 있는 것이다. 테스트 케이스를 test suite로 결합하라.

(TestSuite named: 'Money')
add: (MoneyTestCase selector: #testAdd);
add: (MoneyTestCase selector: #testSubtract);
run


  1. run 을 TestSuite로 전송한 결과는 TestResult 객체이다. 해당 객체는 실패나 오류를 야기한 모든 테스트 케이스를 비롯해 검사도구가 실행된 시간을 기록한다.
이러한 객체들은 모두 이미지에 저장되고 검색되기에 적절하다. 이를 검색도구로 쉽게 저장하고, 가져와서 실행하며, 이전 실행결과와 비교할 수 있다. 


명령 행으로부터 검사도구 실행하기

GNU Smalltalk는 SUnit 검사도구의 실행을 단순화하기 위한 스몰토크 스크립트를 포함하는데, 이를 gst-sunit이라 부른다. gst-sunit에 대한 명령 행은 테스트해야 할 패키지, 파일, 클래스를 명시한다:

-I

--image-file

주어진 이미지 내에서 테스트를 실행한다.


-q

--quiet

프로그램의 출력을 숨긴다. 결과는 여전히 프로그램의 종료 코드를 이용해 전달된다.


-v

--verbose

좀 더 길게 테스트를 실행한다. 특히 이는 현재 어떤 테스트가 실행 중인지 작성하기 위해 gst-sunit를 야기할 것이다.


-f FILE

--file=FILE

필요한 테스트 케이스를 실행하기 전에 FILE 을 로드한다.


-p PACKAGE

--package=PACKAGE

PACKAGE와 그 의존성을 로드하고 실행할 테스트의 집합으로 PACKAGE의 테스트를 추가한다.


CLASS

CLASS*

실행할 테스트 케이스의 집합에 CLASS를 추가한다. 클래스명 다음에 따라오는 별표는 CLASS의 계층구조 내 모든 클래스를 추가한다. 특히 이름이 test로 시작되는 각 선택자는 구분된 테스트 케이스를 구성한다.


VAR=VALUE

VAR 변수를 값과 관련시켜라. 값은 테스팅 환경의 개인설정을 허용한다. 예를 들어, 데이터베이스로 접근해야 할 사용자명은 변수로 명시할 수 있다. 아래와 같은 코드를 이용해 테스트 내부로부터 변수로의 접근이 가능하다:
TestSuitesScripter variableAt: 'mysqluser' ifAbsent: [ 'root' ]
#variableAt: 변형체(variant)는 존재하지 않은데 사용자가 변수를 명시하지 않은 경우 검사도구가 기본 값을 선택해야 하기 때문이다.


Sockets, WebServer, NetClients

GNU Smalltalk는 거의 완전한 TCP, UDP, IP 프로토콜의 추상화를 포함한다. 이러한 라이브러리는 표준 BSD 소켓을 기반으로 하긴 하지만 C 프로그래머가 주로 수동으로 구현해야 하는 선점형 입출력 (preemptive I/O) 혹은 버퍼링과 같은 기능들을 제공한다.


배포판은 여러 테스트를 포함하는데 (대부분이 루프백 테스트로, 클라이언트와 서버 연결을 모두 보여준다), 이러한 테스트들은 Socket 안에 있는 클래스 메서드이다. 해당 코드는 서버와 클라이언트 소켓을 생성하고 이용하는 과정에서 당신을 안내해줄 것이다; 생성이 끝나면 소켓은 표준 스몰토크 스트림과 사실상 동일하게 행동하므로 특별한 문제가 없을 것이다. 상세한 정보는 GNU Smalltalk Library Reference의 "Network programming with Sockets" 절을 참고한다. 라이브러리는 Swazoo나 MySQL 드라이버와 같은 다른 많은 패키지에서도 사용된다.


가장 유명한 인터넷 프로토콜을 구현하는 코드도 있다: FTP, HTTP, NNTP, SMTP, POP3, IMAP. NetClients 패키지에 의해 로드되는 이러한 클래스들은 다중 공공 도메인, 다른 스몰토크 파생어(dialect)에 이용 가능한 무료 소프트웨어 패키지로부터 파생하여 GNU Smalltalk로 이식되었다. 추후 GNU Smalltalk 버전에는 이와 관련된 문서도 포함될 것이다.


GNU Smalltalk를 위한 객체 모델과 XML 파서

패키지 XML로서 로드되는 스몰토크와 관련된 XML 파서 라이브러리는 검증용 XML 파서와 문서 객체 모델(Document Object Model)을 포함한다. 해당 라이브러리는 스몰토크에서 급격하게 표준이 되어 가고 있으며, 이를 기반으로 한 XSLR 해석기는 GNU Smalltalk과도 번들된다 (XPath와 XSL 패키지 참조). 기본 XML 패키지의 부분들은 XML-DOM, XML-SAXParser, XML-SAXDriver, XML-XMLNodeBuilder 패키지를 이용해 독립적으로 로딩될 수 있다.


기타 패키지

다양한 기타 "작은" 패키지들이 제공되는데, 보통은 GNU Smalltalk를 위한 모듈을 작성하는 예로 제공된다 (47 페이지의 5.1절 [라이브러리를 가상 머신으로 연결하기] 참조). 이러한 패키지로는 다음이 포함된다:

  • Complex 복소수를 이용해 투명한 연산을 추가한다.
  • GDBM GNU 데이터베이스 관리자에 대한 인터페이스이다.
  • Digest MD5와 SHA1 알고리즘을 이용해 강력한 해시 값을 암호 표기법으로 재빠르게 계산하기 위해 클래스를 이용하는 두 가지 방법을 제공한다.
  • NCurses ncurses로의 바인딩을 제공한다.
  • Continuations 연속을 위한 더 많은 예제와 테스트를 제공한다 (복잡한 제어흐름을 지원하는 향상된 기능).
  • DebugTools 다른 스몰토크 프로세스를 부착하고 바이트코드 또는 메서드를 따로 따로 실행하기 위한 방법을 제공한다.


Notes

  1. GNU Smalltalk에 대한 Gtk+ 바인딩은 미발달 상태에 있다; Gtk+ 2.0 이상 버전이 설치된 경우 GTK 패키지에서 찾을 수 있다.
  2. 이 문서를 정리하고 있는 2013/12 시점에서는 Gtk+ 바인딩은 완성되어있는 상태라고 봐도 무방하다. gst-browser 를 실행하면 gtk 버전을 볼 수 있다. gnu-smalltalk 3.2.5 현재.
  3. 이번 절에서 언급하는 모든 클래스는 I18N 네임스페이스에 상주한다.
  4. =를 이용한 문자 상등성은 ==를 이용 시보다 빠르다.
  5. ? 메서드는 LcMessagesDomain 클래스 자체엔 적용되지 않고 그 인스턴스에만 적용된다. LcMessageDomain은 Locale의 서브클래스가 아니기 때문이다.
  6. 익스트림 프로그래밍은 팀 워크 (프로그래머가 다른 사람이 타이핑하는 내용을 실시간으로 보는 시점), 잦은 프로그램 테스팅, 증분 설계에 초점을 둔 소프트웨어 공학 기법이다.